/**
* Authors - <some text>
* Project - <some text>
* Description - <some text>
**/


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

#include "llsim.h"




		do {							\
			llsim_printf("sp: clock %d: ", llsim->clock);	\
			llsim_printf(a);				\
		} while (0)

int nr_simulated_instructions = 0;
FILE *inst_trace_fp = NULL, *cycle_trace_fp = NULL;


typedef struct sp_registers_s {
	// 6 32 bit registers (r[0], r[1] don't exist)
	int r[8];

	// 16 bit program counter
	int pc;

	// 32 bit instruction
	int inst;

	// 5 bit opcode
	int opcode;

	// 3 bit destination register index
	int dst;

	// 3 bit source #0 register index
	int src0;

	// 3 bit source #1 register index
	int src1;

	// 32 bit alu #0 operand
	int alu0;

	// 32 bit alu #1 operand
	int alu1;

	// 32 bit alu output
	int aluout;

	// 32 bit immediate field (original 16 bit sign extended)
	int immediate;

	// 32 bit cycle counter
	int cycle_counter;

	// 3 bit control state machine state register
	int ctl_state;

	// control states







} sp_registers_t;

/*
 * Master structure
 */
typedef struct sp_s {
	// local sram

	llsim_memory_t *sram;

	unsigned int memory_image[SP_SRAM_HEIGHT];
	int memory_image_size;

	sp_registers_t *spro, *sprn;
	int instruction_count;
	int start;
} sp_t;

static void sp_reset(sp_t *sp)
{
	sp_registers_t *sprn = sp->sprn;

	memset(sprn, 0, sizeof(*sprn));
}

/*
 * opcodes
 */

















static char opcode_name[32][4] = {"ADD", "SUB", "LSF", "RSF", "AND", "OR"
		"LD", "ST", "U", "U", "U", "U", "U", "U",
		"JLT", "JLE", "JEQ", "JNE", "JIN", "U", "U", "U",
		"HLT", "U", "U", "U", "U", "U", "U", "U"};

static void dump_sram(sp_t *sp)
{
	FILE *fp;
	int i;

	fp = fopen("sram_out.txt", "w");
	if (fp == NULL) {
		printf("couldn't open file sram_out.txt\n");
		exit(1);
	}
	for (i = 0; i < SP_SRAM_HEIGHT; i++)
		fprintf(fp, "%08x\n", llsim_mem_extract(sp->sram, i, 31, 0));
	fclose(fp);
}


static void sp_ctl(sp_t *sp)
{
	sp_registers_t *spro = sp->spro;
	sp_registers_t *sprn = sp->sprn;
	int i;
	char traceExecuteLine[100], traceExecuteLineContent[50],stringToP
	// sp_ctl

	fprintf(cycle_trace_fp, "cycle %d\n", spro->cycle_counter);
	for (i = 2; i <= 7; i++)
		fprintf(cycle_trace_fp, "r%d %08x\n", i, spro->r[i]);
	fprintf(cycle_trace_fp, "pc %08x\n", spro->pc);
	fprintf(cycle_trace_fp, "inst %08x\n", spro->inst);
	fprintf(cycle_trace_fp, "opcode %08x\n", spro->opcode);
	fprintf(cycle_trace_fp, "dst %08x\n", spro->dst);
	fprintf(cycle_trace_fp, "src0 %08x\n", spro->src0);
	fprintf(cycle_trace_fp, "src1 %08x\n", spro->src1);
	fprintf(cycle_trace_fp, "immediate %08x\n", spro->immediate);
	fprintf(cycle_trace_fp, "alu0 %08x\n", spro->alu0);
	fprintf(cycle_trace_fp, "alu1 %08x\n", spro->alu1);
	fprintf(cycle_trace_fp, "aluout %08x\n", spro->aluout);
	fprintf(cycle_trace_fp, "cycle_counter %08x\n", spro->cycle_counter);
	fprintf(cycle_trace_fp, "ctl_state %08x\n\n", spro->ctl_state);

	sprn->cycle_counter = spro->cycle_counter + 1;

	switch (spro->ctl_state) {
	case CTL_STATE_IDLE:
		sprn->pc = 0;
		sp->instruction_count = 0;
		if (sp->start)
			sprn->ctl_state = CTL_STATE_FETCH0;
		break;

	case CTL_STATE_FETCH0:
		llsim_mem_read(sp->sram, spro->pc);
		sprn->ctl_state = CTL_STATE_FETCH1;
		break;

	case CTL_STATE_FETCH1:
		sprn->inst = llsim_mem_extract_dataout(sp->sram, 31, 0);
		sprn->ctl_state = CTL_STATE_DEC0;
		break;

	case CTL_STATE_DEC0:
		sprn->opcode = ((0x3e000000 & spro->inst) >> 25);
		sprn->dst = ((0x01c00000 & spro->inst) >> 22);
		sprn->src0 = ((0x00380000 & spro->inst) >> 19);
		sprn->src1 = ((0x00070000 & spro->inst) >> 16);
		sprn->immediate = (((0x0000ffff & spro->inst) << 16)>>16);
		sprn->ctl_state = CTL_STATE_DEC1;
		break;

	case CTL_STATE_DEC1:

		if (spro->src0==0)
			sprn->alu0 = 0;
		else if (spro->src0==1)
			sprn->alu0 = spro->immediate;
		else
			sprn->alu0 = spro->r[spro->src0];

		if (spro->src1==0)
			sprn->alu1 = 0;
		else if (spro->src1==1)
			sprn->alu1 = spro->immediate;
		else
			sprn->alu1 = spro->r[spro->src1];

		//Print the trace (not including the EXEC part)
		sprintf(stringToPrint,"\n--- instruction %d (%04x) @ PC %d (%04d)",
				sp->instruction_count, sp->instruction_count,
				spro->pc, spro->pc);
		sprintf(temp," ------------------------------------------------------
		strcat(stringToPrint,temp);
		sprintf(temp,"pc = %04d, inst = %08x, ", spro->pc, spro->inst);
		strcat(stringToPrint,temp);
		sprintf(temp,"opcode = %d (%s)", spro->opcode, opcode_name[spro->opcod
		strcat(stringToPrint,temp);
		sprintf(temp,", dst = %d, src0 = %d, ", spro->dst, spro->src0);
		strcat(stringToPrint,temp);
		sprintf(temp,"src1 = %d, immediate = %08x\n", spro->src1, spro->immedia
		strcat(stringToPrint,temp);
		int i,reg;
		for (i=0; i<8; i++)
		{
			if (i==0)
				reg = 0;
			else if (i==1)
				reg = spro->immediate;
			else
				reg = sprn->r[i];

			sprintf(temp,"r[%d] = %08x ", i, reg);
			strcat(stringToPrint,temp);
			if (!((i+1)%4))
				strcat(stringToPrint,"\n");
		}
		fprintf(inst_trace_fp,"%s",stringToPrint);


		sprn->ctl_state = CTL_STATE_EXEC0;

		break;

	case CTL_STATE_EXEC0:

		switch (spro->opcode)
		{

		case ADD:
			sprn->aluout = spro->alu0 + spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case SUB:
			sprn->aluout = spro->alu0 - spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LSF:
			sprn->aluout = spro->alu0 << spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case RSF:
			sprn->aluout = spro->alu0 >> spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case AND:
			sprn->aluout = spro->alu0 & spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case OR:
			sprn->aluout = spro->alu0 | spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case XOR:
			sprn->aluout = spro->alu0 ^ spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LHI:
			sprn->aluout = (spro->alu1 << 16) | (spro->alu0 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LD:
			llsim_mem_read(sp->sram, spro->alu1 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case ST:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLT:
			sprn->aluout = spro->alu0 < spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLE:
			sprn->aluout = spro->alu0 <= spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JEQ:
			sprn->aluout =  spro->alu0 == spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JNE:
			sprn->aluout = spro->alu0 != spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JIN:
		case HLT:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;
		default:
			// Invalid OPCODE, go to fetch0
			sprn->pc = (spro->pc + 1) & 0xffff;
			sprn->ctl_state = CTL_STATE_FETCH0;
			break;
		}
		break;


				fprintf(inst_trace_fp,"%s",traceExecuteLine);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				break;
			}

			switch (spro->opcode)
			{

			case ADD:
			case SUB:
			case LSF:
			case RSF:
			case AND:
			case OR:
			case XOR:
			case LHI:
				sprn->r[spro->dst] = spro->aluout;
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						TRACE_EXEC_ARITH_CONTENT_LINE_PATTERN,
				break;

			case LD:
				sprn->r[spro->dst] = llsim_mem_extract_dataout(sp->sram, 31,
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"R[%d] = MEM[%d] = %08x ",
						spro->dst, spro->alu1,
						sprn->r[spro->dst]);
				break;

			case ST:
				llsim_mem_set_datain(sp->sram, spro->alu0, 31, 0);
				llsim_mem_write(sp->sram, spro->alu1 & 0xffff);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"MEM[%d] = R[%d] = %08x ",
						spro->alu1, spro->src0, spro->alu0);
				break;

			case JLT:
			case JLE:
			case JEQ:
			case JNE:
				if (spro->aluout){
					sprn->r[7] = spro->pc;
					sprn->pc = spro->immediate;
				}else
					sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ",opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case JIN:
				sprn->r[7] = spro->pc;
				sprn->pc = spro->alu0;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ", opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case HLT:
				sprn->ctl_state = CTL_STATE_IDLE;
				sprintf(traceExecuteLineContent,
						"HALT at PC %04x", spro->pc);
				llsim_stop();
				dump_sram(sp);
				break;

			default:
				// Invalid OPCODE, go to fetch0
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				traceExecuteLineContent[0]=0;
				break;
			}

			//Print the execution line to trace
			sprintf(traceExecuteLine, TRACE_EXEC_LINE_PATTERN, traceExecuteLin
            intf(inst_trace_fp,"%s",traceExecuteLine);
			sp->instruction_count = sp->instruction_count+1;

			//Print the final line to trace
			if (spro->opcode==HLT){
				char stringToPrint[100];
				sprintf(stringToPrint,"sim finished at pc %d, %d instructi
                ons",spro->pc,sp->instruction_count);
				fprintf(inst_trace_fp,"%s",stringToPrint);
				fclose(inst_trace_fp);
			}

			sprn->pc = sprn->pc & 0xffff;

			break;
	}
}

static void sp_run(llsim_unit_t *unit)
{
	sp_t *sp = (sp_t *) unit->private;

	if (llsim->reset) {
		sp_reset(sp);
		return;
	}

	sp->sram->read = 0;
	sp->sram->write = 0;

	sp_ctl(sp);
}

static void sp_generate_sram_memory_image(sp_t *sp, char *program_name)
{
	FILE *fp;
	int addr, i;

	fp = fopen(program_name, "r");
	if (fp == NULL) {
		printf("couldn't open file %s\n", program_name);
		exit(1);
	}
	addr = 0;
	while (addr < SP_SRAM_HEIGHT) {
		fscanf(fp, "%08x\n", &sp->memory_image[addr]);
		addr++;
		if (feof(fp))
			break;
	}
	sp->memory_image_size = addr;

	fprintf(inst_trace_fp, "program %s loaded, %d lines\n", program_name);

	for (i = 0; i < sp->memory_image_size; i++)
		llsim_mem_inject(sp->sram, i, sp->memory_image[i], 31, 0);
}

static void sp_register_all_registers(sp_t *sp)
{
	sp_registers_t *spro = sp->spro, *sprn = sp->sprn;

	// registers
	llsim_register_register("sp", "r_0", 32, 0, &spro->r[0], &sprn->r[0]);
	llsim_register_register("sp", "r_1", 32, 0, &spro->r[1], &sprn->r[1]);
	llsim_register_register("sp", "r_2", 32, 0, &spro->r[2], &sprn->r[2]);
	llsim_register_register("sp", "r_3", 32, 0, &spro->r[3], &sprn->r[3]);
	llsim_register_register("sp", "r_4", 32, 0, &spro->r[4], &sprn->r[4]);
	llsim_register_register("sp", "r_5", 32, 0, &spro->r[5], &sprn->r[5]);
	llsim_register_register("sp", "r_6", 32, 0, &spro->r[6], &sprn->r[6]);
	llsim_register_register("sp", "r_7", 32, 0, &spro->r[7], &sprn->r[7]);

	llsim_register_register("sp", "pc", 16, 0, &spro->pc, &sprn->pc);
	llsim_register_register("sp", "inst", 32, 0, &spro->inst, &sprn->inst);
	llsim_register_register("sp", "opcode", 5, 0, &spro->opcode, &sprn->opc
	llsim_register_register("sp", "dst", 3, 0, &spro->dst, &sprn->dst);
	llsim_register_register("sp", "src0", 3, 0, &spro->src0, &sprn->src0);
	llsim_register_register("sp", "src1", 3, 0, &spro->src1, &sprn->src1);
	llsim_register_register("sp", "alu0", 32, 0, &spro->alu0, &sprn->alu0);
}

void sp_init(char *program_name)
{
	llsim_unit_t *llsim_sp_unit;
	llsim_unit_registers_t *llsim_ur;
	sp_t *sp;

	llsim_printf("initializing sp unit\n");

	inst_trace_fp = fopen("inst_trace.txt", "w");
	if (inst_trace_fp == NULL) {
		printf("couldn't open file inst_trace.txt\n");
		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);
}

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

#include "llsim.h"




		do {							\
			llsim_printf("sp: clock %d: ", llsim->clock);	\
			llsim_printf(a);				\
		} while (0)

int nr_simulated_instructions = 0;
FILE *inst_trace_fp = NULL, *cycle_trace_fp = NULL;


typedef struct sp_registers_s {
	// 6 32 bit registers (r[0], r[1] don't exist)
	int r[8];

	// 16 bit program counter
	int pc;

	// 32 bit instruction
	int inst;

	// 5 bit opcode
	int opcode;

	// 3 bit destination register index
	int dst;

	// 3 bit source #0 register index
	int src0;

	// 3 bit source #1 register index
	int src1;

	// 32 bit alu #0 operand
	int alu0;

	// 32 bit alu #1 operand
	int alu1;

	// 32 bit alu output
	int aluout;

	// 32 bit immediate field (original 16 bit sign extended)
	int immediate;

	// 32 bit cycle counter
	int cycle_counter;

	// 3 bit control state machine state register
	int ctl_state;

	// control states







} sp_registers_t;

/*
 * Master structure
 */
typedef struct sp_s {
	// local sram

	llsim_memory_t *sram;

	unsigned int memory_image[SP_SRAM_HEIGHT];
	int memory_image_size;

	sp_registers_t *spro, *sprn;
	int instruction_count;
	int start;
} sp_t;

static void sp_reset(sp_t *sp)
{
	sp_registers_t *sprn = sp->sprn;

	memset(sprn, 0, sizeof(*sprn));
}

/*
 * opcodes
 */

















static char opcode_name[32][4] = {"ADD", "SUB", "LSF", "RSF", "AND", "OR"
		"LD", "ST", "U", "U", "U", "U", "U", "U",
		"JLT", "JLE", "JEQ", "JNE", "JIN", "U", "U", "U",
		"HLT", "U", "U", "U", "U", "U", "U", "U"};

static void dump_sram(sp_t *sp)
{
	FILE *fp;
	int i;

	fp = fopen("sram_out.txt", "w");
	if (fp == NULL) {
		printf("couldn't open file sram_out.txt\n");
		exit(1);
	}
	for (i = 0; i < SP_SRAM_HEIGHT; i++)
		fprintf(fp, "%08x\n", llsim_mem_extract(sp->sram, i, 31, 0));
	fclose(fp);
}


static void sp_ctl(sp_t *sp)
{
	sp_registers_t *spro = sp->spro;
	sp_registers_t *sprn = sp->sprn;
	int i;
	char traceExecuteLine[100], traceExecuteLineContent[50],stringToP
	// sp_ctl

	fprintf(cycle_trace_fp, "cycle %d\n", spro->cycle_counter);
	for (i = 2; i <= 7; i++)
		fprintf(cycle_trace_fp, "r%d %08x\n", i, spro->r[i]);
	fprintf(cycle_trace_fp, "pc %08x\n", spro->pc);
	fprintf(cycle_trace_fp, "inst %08x\n", spro->inst);
	fprintf(cycle_trace_fp, "opcode %08x\n", spro->opcode);
	fprintf(cycle_trace_fp, "dst %08x\n", spro->dst);
	fprintf(cycle_trace_fp, "src0 %08x\n", spro->src0);
	fprintf(cycle_trace_fp, "src1 %08x\n", spro->src1);
	fprintf(cycle_trace_fp, "immediate %08x\n", spro->immediate);
	fprintf(cycle_trace_fp, "alu0 %08x\n", spro->alu0);
	fprintf(cycle_trace_fp, "alu1 %08x\n", spro->alu1);
	fprintf(cycle_trace_fp, "aluout %08x\n", spro->aluout);
	fprintf(cycle_trace_fp, "cycle_counter %08x\n", spro->cycle_counter);
	fprintf(cycle_trace_fp, "ctl_state %08x\n\n", spro->ctl_state);

	sprn->cycle_counter = spro->cycle_counter + 1;

	switch (spro->ctl_state) {
	case CTL_STATE_IDLE:
		sprn->pc = 0;
		sp->instruction_count = 0;
		if (sp->start)
			sprn->ctl_state = CTL_STATE_FETCH0;
		break;

	case CTL_STATE_FETCH0:
		llsim_mem_read(sp->sram, spro->pc);
		sprn->ctl_state = CTL_STATE_FETCH1;
		break;

	case CTL_STATE_FETCH1:
		sprn->inst = llsim_mem_extract_dataout(sp->sram, 31, 0);
		sprn->ctl_state = CTL_STATE_DEC0;
		break;

	case CTL_STATE_DEC0:
		sprn->opcode = ((0x3e000000 & spro->inst) >> 25);
		sprn->dst = ((0x01c00000 & spro->inst) >> 22);
		sprn->src0 = ((0x00380000 & spro->inst) >> 19);
		sprn->src1 = ((0x00070000 & spro->inst) >> 16);
		sprn->immediate = (((0x0000ffff & spro->inst) << 16)>>16);
		sprn->ctl_state = CTL_STATE_DEC1;
		break;

	case CTL_STATE_DEC1:

		if (spro->src0==0)
			sprn->alu0 = 0;
		else if (spro->src0==1)
			sprn->alu0 = spro->immediate;
		else
			sprn->alu0 = spro->r[spro->src0];

		if (spro->src1==0)
			sprn->alu1 = 0;
		else if (spro->src1==1)
			sprn->alu1 = spro->immediate;
		else
			sprn->alu1 = spro->r[spro->src1];

		//Print the trace (not including the EXEC part)
		sprintf(stringToPrint,"\n--- instruction %d (%04x) @ PC %d (%04d)",
				sp->instruction_count, sp->instruction_count,
				spro->pc, spro->pc);
		sprintf(temp," ------------------------------------------------------
		strcat(stringToPrint,temp);
		sprintf(temp,"pc = %04d, inst = %08x, ", spro->pc, spro->inst);
		strcat(stringToPrint,temp);
		sprintf(temp,"opcode = %d (%s)", spro->opcode, opcode_name[spro->opcod
		strcat(stringToPrint,temp);
		sprintf(temp,", dst = %d, src0 = %d, ", spro->dst, spro->src0);
		strcat(stringToPrint,temp);
		sprintf(temp,"src1 = %d, immediate = %08x\n", spro->src1, spro->immedia
		strcat(stringToPrint,temp);
		int i,reg;
		for (i=0; i<8; i++)
		{
			if (i==0)
				reg = 0;
			else if (i==1)
				reg = spro->immediate;
			else
				reg = sprn->r[i];

			sprintf(temp,"r[%d] = %08x ", i, reg);
			strcat(stringToPrint,temp);
			if (!((i+1)%4))
				strcat(stringToPrint,"\n");
		}
		fprintf(inst_trace_fp,"%s",stringToPrint);


		sprn->ctl_state = CTL_STATE_EXEC0;

		break;

	case CTL_STATE_EXEC0:

		switch (spro->opcode)
		{

		case ADD:
			sprn->aluout = spro->alu0 + spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case SUB:
			sprn->aluout = spro->alu0 - spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LSF:
			sprn->aluout = spro->alu0 << spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case RSF:
			sprn->aluout = spro->alu0 >> spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case AND:
			sprn->aluout = spro->alu0 & spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case OR:
			sprn->aluout = spro->alu0 | spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case XOR:
			sprn->aluout = spro->alu0 ^ spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LHI:
			sprn->aluout = (spro->alu1 << 16) | (spro->alu0 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LD:
			llsim_mem_read(sp->sram, spro->alu1 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case ST:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLT:
			sprn->aluout = spro->alu0 < spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLE:
			sprn->aluout = spro->alu0 <= spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JEQ:
			sprn->aluout =  spro->alu0 == spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JNE:
			sprn->aluout = spro->alu0 != spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JIN:
		case HLT:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;
		default:
			// Invalid OPCODE, go to fetch0
			sprn->pc = (spro->pc + 1) & 0xffff;
			sprn->ctl_state = CTL_STATE_FETCH0;
			break;
		}
		break;


				fprintf(inst_trace_fp,"%s",traceExecuteLine);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				break;
			}

			switch (spro->opcode)
			{

			case ADD:
			case SUB:
			case LSF:
			case RSF:
			case AND:
			case OR:
			case XOR:
			case LHI:
				sprn->r[spro->dst] = spro->aluout;
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						TRACE_EXEC_ARITH_CONTENT_LINE_PATTERN,
				break;

			case LD:
				sprn->r[spro->dst] = llsim_mem_extract_dataout(sp->sram, 31,
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"R[%d] = MEM[%d] = %08x ",
						spro->dst, spro->alu1,
						sprn->r[spro->dst]);
				break;

			case ST:
				llsim_mem_set_datain(sp->sram, spro->alu0, 31, 0);
				llsim_mem_write(sp->sram, spro->alu1 & 0xffff);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"MEM[%d] = R[%d] = %08x ",
						spro->alu1, spro->src0, spro->alu0);
				break;

			case JLT:
			case JLE:
			case JEQ:
			case JNE:
				if (spro->aluout){
					sprn->r[7] = spro->pc;
					sprn->pc = spro->immediate;
				}else
					sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ",opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case JIN:
				sprn->r[7] = spro->pc;
				sprn->pc = spro->alu0;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ", opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case HLT:
				sprn->ctl_state = CTL_STATE_IDLE;
				sprintf(traceExecuteLineContent,
						"HALT at PC %04x", spro->pc);
				llsim_stop();
				dump_sram(sp);
				break;

			default:
				// Invalid OPCODE, go to fetch0
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				traceExecuteLineContent[0]=0;
				break;
			}

			//Print the execution line to trace
			sprintf(traceExecuteLine, TRACE_EXEC_LINE_PATTERN, traceExecuteLin
            intf(inst_trace_fp,"%s",traceExecuteLine);
			sp->instruction_count = sp->instruction_count+1;

			//Print the final line to trace
			if (spro->opcode==HLT){
				char stringToPrint[100];
				sprintf(stringToPrint,"sim finished at pc %d, %d instructi
                ons",spro->pc,sp->instruction_count);
				fprintf(inst_trace_fp,"%s",stringToPrint);
				fclose(inst_trace_fp);
			}

			sprn->pc = sprn->pc & 0xffff;

			break;
	}
}

static void sp_run(llsim_unit_t *unit)
{
	sp_t *sp = (sp_t *) unit->private;

	if (llsim->reset) {
		sp_reset(sp);
		return;
	}

	sp->sram->read = 0;
	sp->sram->write = 0;

	sp_ctl(sp);
}

static void sp_generate_sram_memory_image(sp_t *sp, char *program_name)
{
	FILE *fp;
	int addr, i;

	fp = fopen(program_name, "r");
	if (fp == NULL) {
		printf("couldn't open file %s\n", program_name);
		exit(1);
	}
	addr = 0;
	while (addr < SP_SRAM_HEIGHT) {
		fscanf(fp, "%08x\n", &sp->memory_image[addr]);
		addr++;
		if (feof(fp))
			break;
	}
	sp->memory_image_size = addr;

	fprintf(inst_trace_fp, "program %s loaded, %d lines\n", program_name);

	for (i = 0; i < sp->memory_image_size; i++)
		llsim_mem_inject(sp->sram, i, sp->memory_image[i], 31, 0);
}

static void sp_register_all_registers(sp_t *sp)
{
	sp_registers_t *spro = sp->spro, *sprn = sp->sprn;

	// registers
	llsim_register_register("sp", "r_0", 32, 0, &spro->r[0], &sprn->r[0]);
	llsim_register_register("sp", "r_1", 32, 0, &spro->r[1], &sprn->r[1]);
	llsim_register_register("sp", "r_2", 32, 0, &spro->r[2], &sprn->r[2]);
	llsim_register_register("sp", "r_3", 32, 0, &spro->r[3], &sprn->r[3]);
	llsim_register_register("sp", "r_4", 32, 0, &spro->r[4], &sprn->r[4]);
	llsim_register_register("sp", "r_5", 32, 0, &spro->r[5], &sprn->r[5]);
	llsim_register_register("sp", "r_6", 32, 0, &spro->r[6], &sprn->r[6]);
	llsim_register_register("sp", "r_7", 32, 0, &spro->r[7], &sprn->r[7]);

	llsim_register_register("sp", "pc", 16, 0, &spro->pc, &sprn->pc);
	llsim_register_register("sp", "inst", 32, 0, &spro->inst, &sprn->inst);
	llsim_register_register("sp", "opcode", 5, 0, &spro->opcode, &sprn->opc
	llsim_register_register("sp", "dst", 3, 0, &spro->dst, &sprn->dst);
	llsim_register_register("sp", "src0", 3, 0, &spro->src0, &sprn->src0);
	llsim_register_register("sp", "src1", 3, 0, &spro->src1, &sprn->src1);
	llsim_register_register("sp", "alu0", 32, 0, &spro->alu0, &sprn->alu0);
}

void sp_init(char *program_name)
{
	llsim_unit_t *llsim_sp_unit;
	llsim_unit_registers_t *llsim_ur;
	sp_t *sp;

	llsim_printf("initializing sp unit\n");

	inst_trace_fp = fopen("inst_trace.txt", "w");
	if (inst_trace_fp == NULL) {
		printf("couldn't open file inst_trace.txt\n");
		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);
}

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

#include "llsim.h"




		do {							\
			llsim_printf("sp: clock %d: ", llsim->clock);	\
			llsim_printf(a);				\
		} while (0)

int nr_simulated_instructions = 0;
FILE *inst_trace_fp = NULL, *cycle_trace_fp = NULL;


typedef struct sp_registers_s {
	// 6 32 bit registers (r[0], r[1] don't exist)
	int r[8];

	// 16 bit program counter
	int pc;

	// 32 bit instruction
	int inst;

	// 5 bit opcode
	int opcode;

	// 3 bit destination register index
	int dst;

	// 3 bit source #0 register index
	int src0;

	// 3 bit source #1 register index
	int src1;

	// 32 bit alu #0 operand
	int alu0;

	// 32 bit alu #1 operand
	int alu1;

	// 32 bit alu output
	int aluout;

	// 32 bit immediate field (original 16 bit sign extended)
	int immediate;

	// 32 bit cycle counter
	int cycle_counter;

	// 3 bit control state machine state register
	int ctl_state;

	// control states







} sp_registers_t;

/*
 * Master structure
 */
typedef struct sp_s {
	// local sram

	llsim_memory_t *sram;

	unsigned int memory_image[SP_SRAM_HEIGHT];
	int memory_image_size;

	sp_registers_t *spro, *sprn;
	int instruction_count;
	int start;
} sp_t;

static void sp_reset(sp_t *sp)
{
	sp_registers_t *sprn = sp->sprn;

	memset(sprn, 0, sizeof(*sprn));
}

/*
 * opcodes
 */

















static char opcode_name[32][4] = {"ADD", "SUB", "LSF", "RSF", "AND", "OR"
		"LD", "ST", "U", "U", "U", "U", "U", "U",
		"JLT", "JLE", "JEQ", "JNE", "JIN", "U", "U", "U",
		"HLT", "U", "U", "U", "U", "U", "U", "U"};

static void dump_sram(sp_t *sp)
{
	FILE *fp;
	int i;

	fp = fopen("sram_out.txt", "w");
	if (fp == NULL) {
		printf("couldn't open file sram_out.txt\n");
		exit(1);
	}
	for (i = 0; i < SP_SRAM_HEIGHT; i++)
		fprintf(fp, "%08x\n", llsim_mem_extract(sp->sram, i, 31, 0));
	fclose(fp);
}


static void sp_ctl(sp_t *sp)
{
	sp_registers_t *spro = sp->spro;
	sp_registers_t *sprn = sp->sprn;
	int i;
	char traceExecuteLine[100], traceExecuteLineContent[50],stringToP
	// sp_ctl

	fprintf(cycle_trace_fp, "cycle %d\n", spro->cycle_counter);
	for (i = 2; i <= 7; i++)
		fprintf(cycle_trace_fp, "r%d %08x\n", i, spro->r[i]);
	fprintf(cycle_trace_fp, "pc %08x\n", spro->pc);
	fprintf(cycle_trace_fp, "inst %08x\n", spro->inst);
	fprintf(cycle_trace_fp, "opcode %08x\n", spro->opcode);
	fprintf(cycle_trace_fp, "dst %08x\n", spro->dst);
	fprintf(cycle_trace_fp, "src0 %08x\n", spro->src0);
	fprintf(cycle_trace_fp, "src1 %08x\n", spro->src1);
	fprintf(cycle_trace_fp, "immediate %08x\n", spro->immediate);
	fprintf(cycle_trace_fp, "alu0 %08x\n", spro->alu0);
	fprintf(cycle_trace_fp, "alu1 %08x\n", spro->alu1);
	fprintf(cycle_trace_fp, "aluout %08x\n", spro->aluout);
	fprintf(cycle_trace_fp, "cycle_counter %08x\n", spro->cycle_counter);
	fprintf(cycle_trace_fp, "ctl_state %08x\n\n", spro->ctl_state);

	sprn->cycle_counter = spro->cycle_counter + 1;

	switch (spro->ctl_state) {
	case CTL_STATE_IDLE:
		sprn->pc = 0;
		sp->instruction_count = 0;
		if (sp->start)
			sprn->ctl_state = CTL_STATE_FETCH0;
		break;

	case CTL_STATE_FETCH0:
		llsim_mem_read(sp->sram, spro->pc);
		sprn->ctl_state = CTL_STATE_FETCH1;
		break;

	case CTL_STATE_FETCH1:
		sprn->inst = llsim_mem_extract_dataout(sp->sram, 31, 0);
		sprn->ctl_state = CTL_STATE_DEC0;
		break;

	case CTL_STATE_DEC0:
		sprn->opcode = ((0x3e000000 & spro->inst) >> 25);
		sprn->dst = ((0x01c00000 & spro->inst) >> 22);
		sprn->src0 = ((0x00380000 & spro->inst) >> 19);
		sprn->src1 = ((0x00070000 & spro->inst) >> 16);
		sprn->immediate = (((0x0000ffff & spro->inst) << 16)>>16);
		sprn->ctl_state = CTL_STATE_DEC1;
		break;

	case CTL_STATE_DEC1:

		if (spro->src0==0)
			sprn->alu0 = 0;
		else if (spro->src0==1)
			sprn->alu0 = spro->immediate;
		else
			sprn->alu0 = spro->r[spro->src0];

		if (spro->src1==0)
			sprn->alu1 = 0;
		else if (spro->src1==1)
			sprn->alu1 = spro->immediate;
		else
			sprn->alu1 = spro->r[spro->src1];

		//Print the trace (not including the EXEC part)
		sprintf(stringToPrint,"\n--- instruction %d (%04x) @ PC %d (%04d)",
				sp->instruction_count, sp->instruction_count,
				spro->pc, spro->pc);
		sprintf(temp," ------------------------------------------------------
		strcat(stringToPrint,temp);
		sprintf(temp,"pc = %04d, inst = %08x, ", spro->pc, spro->inst);
		strcat(stringToPrint,temp);
		sprintf(temp,"opcode = %d (%s)", spro->opcode, opcode_name[spro->opcod
		strcat(stringToPrint,temp);
		sprintf(temp,", dst = %d, src0 = %d, ", spro->dst, spro->src0);
		strcat(stringToPrint,temp);
		sprintf(temp,"src1 = %d, immediate = %08x\n", spro->src1, spro->immedia
		strcat(stringToPrint,temp);
		int i,reg;
		for (i=0; i<8; i++)
		{
			if (i==0)
				reg = 0;
			else if (i==1)
				reg = spro->immediate;
			else
				reg = sprn->r[i];

			sprintf(temp,"r[%d] = %08x ", i, reg);
			strcat(stringToPrint,temp);
			if (!((i+1)%4))
				strcat(stringToPrint,"\n");
		}
		fprintf(inst_trace_fp,"%s",stringToPrint);


		sprn->ctl_state = CTL_STATE_EXEC0;

		break;

	case CTL_STATE_EXEC0:

		switch (spro->opcode)
		{

		case ADD:
			sprn->aluout = spro->alu0 + spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case SUB:
			sprn->aluout = spro->alu0 - spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LSF:
			sprn->aluout = spro->alu0 << spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case RSF:
			sprn->aluout = spro->alu0 >> spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case AND:
			sprn->aluout = spro->alu0 & spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case OR:
			sprn->aluout = spro->alu0 | spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case XOR:
			sprn->aluout = spro->alu0 ^ spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LHI:
			sprn->aluout = (spro->alu1 << 16) | (spro->alu0 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LD:
			llsim_mem_read(sp->sram, spro->alu1 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case ST:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLT:
			sprn->aluout = spro->alu0 < spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLE:
			sprn->aluout = spro->alu0 <= spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JEQ:
			sprn->aluout =  spro->alu0 == spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JNE:
			sprn->aluout = spro->alu0 != spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JIN:
		case HLT:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;
		default:
			// Invalid OPCODE, go to fetch0
			sprn->pc = (spro->pc + 1) & 0xffff;
			sprn->ctl_state = CTL_STATE_FETCH0;
			break;
		}
		break;


				fprintf(inst_trace_fp,"%s",traceExecuteLine);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				break;
			}

			switch (spro->opcode)
			{

			case ADD:
			case SUB:
			case LSF:
			case RSF:
			case AND:
			case OR:
			case XOR:
			case LHI:
				sprn->r[spro->dst] = spro->aluout;
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						TRACE_EXEC_ARITH_CONTENT_LINE_PATTERN,
				break;

			case LD:
				sprn->r[spro->dst] = llsim_mem_extract_dataout(sp->sram, 31,
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"R[%d] = MEM[%d] = %08x ",
						spro->dst, spro->alu1,
						sprn->r[spro->dst]);
				break;

			case ST:
				llsim_mem_set_datain(sp->sram, spro->alu0, 31, 0);
				llsim_mem_write(sp->sram, spro->alu1 & 0xffff);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"MEM[%d] = R[%d] = %08x ",
						spro->alu1, spro->src0, spro->alu0);
				break;

			case JLT:
			case JLE:
			case JEQ:
			case JNE:
				if (spro->aluout){
					sprn->r[7] = spro->pc;
					sprn->pc = spro->immediate;
				}else
					sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ",opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case JIN:
				sprn->r[7] = spro->pc;
				sprn->pc = spro->alu0;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ", opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case HLT:
				sprn->ctl_state = CTL_STATE_IDLE;
				sprintf(traceExecuteLineContent,
						"HALT at PC %04x", spro->pc);
				llsim_stop();
				dump_sram(sp);
				break;

			default:
				// Invalid OPCODE, go to fetch0
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				traceExecuteLineContent[0]=0;
				break;
			}

			//Print the execution line to trace
			sprintf(traceExecuteLine, TRACE_EXEC_LINE_PATTERN, traceExecuteLin
            intf(inst_trace_fp,"%s",traceExecuteLine);
			sp->instruction_count = sp->instruction_count+1;

			//Print the final line to trace
			if (spro->opcode==HLT){
				char stringToPrint[100];
				sprintf(stringToPrint,"sim finished at pc %d, %d instructi
                ons",spro->pc,sp->instruction_count);
				fprintf(inst_trace_fp,"%s",stringToPrint);
				fclose(inst_trace_fp);
			}

			sprn->pc = sprn->pc & 0xffff;

			break;
	}
}

static void sp_run(llsim_unit_t *unit)
{
	sp_t *sp = (sp_t *) unit->private;

	if (llsim->reset) {
		sp_reset(sp);
		return;
	}

	sp->sram->read = 0;
	sp->sram->write = 0;

	sp_ctl(sp);
}

static void sp_generate_sram_memory_image(sp_t *sp, char *program_name)
{
	FILE *fp;
	int addr, i;

	fp = fopen(program_name, "r");
	if (fp == NULL) {
		printf("couldn't open file %s\n", program_name);
		exit(1);
	}
	addr = 0;
	while (addr < SP_SRAM_HEIGHT) {
		fscanf(fp, "%08x\n", &sp->memory_image[addr]);
		addr++;
		if (feof(fp))
			break;
	}
	sp->memory_image_size = addr;

	fprintf(inst_trace_fp, "program %s loaded, %d lines\n", program_name);

	for (i = 0; i < sp->memory_image_size; i++)
		llsim_mem_inject(sp->sram, i, sp->memory_image[i], 31, 0);
}

static void sp_register_all_registers(sp_t *sp)
{
	sp_registers_t *spro = sp->spro, *sprn = sp->sprn;

	// registers
	llsim_register_register("sp", "r_0", 32, 0, &spro->r[0], &sprn->r[0]);
	llsim_register_register("sp", "r_1", 32, 0, &spro->r[1], &sprn->r[1]);
	llsim_register_register("sp", "r_2", 32, 0, &spro->r[2], &sprn->r[2]);
	llsim_register_register("sp", "r_3", 32, 0, &spro->r[3], &sprn->r[3]);
	llsim_register_register("sp", "r_4", 32, 0, &spro->r[4], &sprn->r[4]);
	llsim_register_register("sp", "r_5", 32, 0, &spro->r[5], &sprn->r[5]);
	llsim_register_register("sp", "r_6", 32, 0, &spro->r[6], &sprn->r[6]);
	llsim_register_register("sp", "r_7", 32, 0, &spro->r[7], &sprn->r[7]);

	llsim_register_register("sp", "pc", 16, 0, &spro->pc, &sprn->pc);
	llsim_register_register("sp", "inst", 32, 0, &spro->inst, &sprn->inst);
	llsim_register_register("sp", "opcode", 5, 0, &spro->opcode, &sprn->opc
	llsim_register_register("sp", "dst", 3, 0, &spro->dst, &sprn->dst);
	llsim_register_register("sp", "src0", 3, 0, &spro->src0, &sprn->src0);
	llsim_register_register("sp", "src1", 3, 0, &spro->src1, &sprn->src1);
	llsim_register_register("sp", "alu0", 32, 0, &spro->alu0, &sprn->alu0);
}

void sp_init(char *program_name)
{
	llsim_unit_t *llsim_sp_unit;
	llsim_unit_registers_t *llsim_ur;
	sp_t *sp;

	llsim_printf("initializing sp unit\n");

	inst_trace_fp = fopen("inst_trace.txt", "w");
	if (inst_trace_fp == NULL) {
		printf("couldn't open file inst_trace.txt\n");
		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);
}

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

#include "llsim.h"




		do {							\
			llsim_printf("sp: clock %d: ", llsim->clock);	\
			llsim_printf(a);				\
		} while (0)

int nr_simulated_instructions = 0;
FILE *inst_trace_fp = NULL, *cycle_trace_fp = NULL;


typedef struct sp_registers_s {
	// 6 32 bit registers (r[0], r[1] don't exist)
	int r[8];

	// 16 bit program counter
	int pc;

	// 32 bit instruction
	int inst;

	// 5 bit opcode
	int opcode;

	// 3 bit destination register index
	int dst;

	// 3 bit source #0 register index
	int src0;

	// 3 bit source #1 register index
	int src1;

	// 32 bit alu #0 operand
	int alu0;

	// 32 bit alu #1 operand
	int alu1;

	// 32 bit alu output
	int aluout;

	// 32 bit immediate field (original 16 bit sign extended)
	int immediate;

	// 32 bit cycle counter
	int cycle_counter;

	// 3 bit control state machine state register
	int ctl_state;

	// control states







} sp_registers_t;

/*
 * Master structure
 */
typedef struct sp_s {
	// local sram

	llsim_memory_t *sram;

	unsigned int memory_image[SP_SRAM_HEIGHT];
	int memory_image_size;

	sp_registers_t *spro, *sprn;
	int instruction_count;
	int start;
} sp_t;

static void sp_reset(sp_t *sp)
{
	sp_registers_t *sprn = sp->sprn;

	memset(sprn, 0, sizeof(*sprn));
}

/*
 * opcodes
 */

















static char opcode_name[32][4] = {"ADD", "SUB", "LSF", "RSF", "AND", "OR"
		"LD", "ST", "U", "U", "U", "U", "U", "U",
		"JLT", "JLE", "JEQ", "JNE", "JIN", "U", "U", "U",
		"HLT", "U", "U", "U", "U", "U", "U", "U"};

static void dump_sram(sp_t *sp)
{
	FILE *fp;
	int i;

	fp = fopen("sram_out.txt", "w");
	if (fp == NULL) {
		printf("couldn't open file sram_out.txt\n");
		exit(1);
	}
	for (i = 0; i < SP_SRAM_HEIGHT; i++)
		fprintf(fp, "%08x\n", llsim_mem_extract(sp->sram, i, 31, 0));
	fclose(fp);
}


static void sp_ctl(sp_t *sp)
{
	sp_registers_t *spro = sp->spro;
	sp_registers_t *sprn = sp->sprn;
	int i;
	char traceExecuteLine[100], traceExecuteLineContent[50],stringToP
	// sp_ctl

	fprintf(cycle_trace_fp, "cycle %d\n", spro->cycle_counter);
	for (i = 2; i <= 7; i++)
		fprintf(cycle_trace_fp, "r%d %08x\n", i, spro->r[i]);
	fprintf(cycle_trace_fp, "pc %08x\n", spro->pc);
	fprintf(cycle_trace_fp, "inst %08x\n", spro->inst);
	fprintf(cycle_trace_fp, "opcode %08x\n", spro->opcode);
	fprintf(cycle_trace_fp, "dst %08x\n", spro->dst);
	fprintf(cycle_trace_fp, "src0 %08x\n", spro->src0);
	fprintf(cycle_trace_fp, "src1 %08x\n", spro->src1);
	fprintf(cycle_trace_fp, "immediate %08x\n", spro->immediate);
	fprintf(cycle_trace_fp, "alu0 %08x\n", spro->alu0);
	fprintf(cycle_trace_fp, "alu1 %08x\n", spro->alu1);
	fprintf(cycle_trace_fp, "aluout %08x\n", spro->aluout);
	fprintf(cycle_trace_fp, "cycle_counter %08x\n", spro->cycle_counter);
	fprintf(cycle_trace_fp, "ctl_state %08x\n\n", spro->ctl_state);
		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);
	sprn->cycle_counter = spro->cycle_counter + 1;

	switch (spro->ctl_state) {
	case CTL_STATE_IDLE:
		sprn->pc = 0;
		sp->instruction_count = 0;
		if (sp->start)
			sprn->ctl_state = CTL_STATE_FETCH0;
		break;

	case CTL_STATE_FETCH0:
		llsim_mem_read(sp->sram, spro->pc);
		sprn->ctl_state = CTL_STATE_FETCH1;
		break;

	case CTL_STATE_FETCH1:
		sprn->inst = llsim_mem_extract_dataout(sp->sram, 31, 0);
		sprn->ctl_state = CTL_STATE_DEC0;
		break;

	case CTL_STATE_DEC0:
		sprn->opcode = ((0x3e000000 & spro->inst) >> 25);
		sprn->dst = ((0x01c00000 & spro->inst) >> 22);
		sprn->src0 = ((0x00380000 & spro->inst) >> 19);
		sprn->src1 = ((0x00070000 & spro->inst) >> 16);
		sprn->immediate = (((0x0000ffff & spro->inst) << 16)>>16);
		sprn->ctl_state = CTL_STATE_DEC1;
		break;

	case CTL_STATE_DEC1:

		if (spro->src0==0)
			sprn->alu0 = 0;
		else if (spro->src0==1)
			sprn->alu0 = spro->immediate;
		else
			sprn->alu0 = spro->r[spro->src0];

		if (spro->src1==0)
			sprn->alu1 = 0;
		else if (spro->src1==1)
			sprn->alu1 = spro->immediate;
		else
			sprn->alu1 = spro->r[spro->src1];

		//Print the trace (not including the EXEC part)
		sprintf(stringToPrint,"\n--- instruction %d (%04x) @ PC %d (%04d)",
				sp->instruction_count, sp->instruction_count,
				spro->pc, spro->pc);
		sprintf(temp," ------------------------------------------------------
		strcat(stringToPrint,temp);
		sprintf(temp,"pc = %04d, inst = %08x, ", spro->pc, spro->inst);
		strcat(stringToPrint,temp);
		sprintf(temp,"opcode = %d (%s)", spro->opcode, opcode_name[spro->opcod
		strcat(stringToPrint,temp);
		sprintf(temp,", dst = %d, src0 = %d, ", spro->dst, spro->src0);
		strcat(stringToPrint,temp);
		sprintf(temp,"src1 = %d, immediate = %08x\n", spro->src1, spro->immedia
		strcat(stringToPrint,temp);
		int i,reg;
		for (i=0; i<8; i++)
		{
			if (i==0)
				reg = 0;
			else if (i==1)
				reg = spro->immediate;
			else
				reg = sprn->r[i];

			sprintf(temp,"r[%d] = %08x ", i, reg);
			strcat(stringToPrint,temp);
			if (!((i+1)%4))
				strcat(stringToPrint,"\n");
		}
		fprintf(inst_trace_fp,"%s",stringToPrint);


		sprn->ctl_state = CTL_STATE_EXEC0;

		break;

	case CTL_STATE_EXEC0:

		switch (spro->opcode)
		{

		case ADD:
			sprn->aluout = spro->alu0 + spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case SUB:
			sprn->aluout = spro->alu0 - spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LSF:
			sprn->aluout = spro->alu0 << spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case RSF:
			sprn->aluout = spro->alu0 >> spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case AND:
			sprn->aluout = spro->alu0 & spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case OR:
			sprn->aluout = spro->alu0 | spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case XOR:
			sprn->aluout = spro->alu0 ^ spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LHI:
			sprn->aluout = (spro->alu1 << 16) | (spro->alu0 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LD:
			llsim_mem_read(sp->sram, spro->alu1 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case ST:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLT:
			sprn->aluout = spro->alu0 < spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLE:
			sprn->aluout = spro->alu0 <= spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JEQ:
			sprn->aluout =  spro->alu0 == spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JNE:
			sprn->aluout = spro->alu0 != spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JIN:
		case HLT:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;
		default:
			// Invalid OPCODE, go to fetch0
			sprn->pc = (spro->pc + 1) & 0xffff;
			sprn->ctl_state = CTL_STATE_FETCH0;
			break;
		}
		break;


				fprintf(inst_trace_fp,"%s",traceExecuteLine);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				break;
			}

			switch (spro->opcode)
			{

			case ADD:
			case SUB:
			case LSF:
			case RSF:
			case AND:
			case OR:
			case XOR:
			case LHI:
				sprn->r[spro->dst] = spro->aluout;
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						TRACE_EXEC_ARITH_CONTENT_LINE_PATTERN,
				break;

			case LD:
				sprn->r[spro->dst] = llsim_mem_extract_dataout(sp->sram, 31,
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"R[%d] = MEM[%d] = %08x ",
						spro->dst, spro->alu1,
						sprn->r[spro->dst]);
				break;

			case ST:
				llsim_mem_set_datain(sp->sram, spro->alu0, 31, 0);
				llsim_mem_write(sp->sram, spro->alu1 & 0xffff);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"MEM[%d] = R[%d] = %08x ",
						spro->alu1, spro->src0, spro->alu0);
				break;

			case JLT:
			case JLE:
			case JEQ:
			case JNE:
				if (spro->aluout){
					sprn->r[7] = spro->pc;
					sprn->pc = spro->immediate;
				}else
					sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ",opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case JIN:
				sprn->r[7] = spro->pc;
				sprn->pc = spro->alu0;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ", opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case HLT:
				sprn->ctl_state = CTL_STATE_IDLE;
				sprintf(traceExecuteLineContent,
						"HALT at PC %04x", spro->pc);
				llsim_stop();
				dump_sram(sp);
				break;

			default:
				// Invalid OPCODE, go to fetch0
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				traceExecuteLineContent[0]=0;
				break;
			}

			//Print the execution line to trace
			sprintf(traceExecuteLine, TRACE_EXEC_LINE_PATTERN, traceExecuteLin
            intf(inst_trace_fp,"%s",traceExecuteLine);
			sp->instruction_count = sp->instruction_count+1;

			//Print the final line to trace
			if (spro->opcode==HLT){
				char stringToPrint[100];
				sprintf(stringToPrint,"sim finished at pc %d, %d instructi
                ons",spro->pc,sp->instruction_count);
				fprintf(inst_trace_fp,"%s",stringToPrint);
				fclose(inst_trace_fp);
			}

			sprn->pc = sprn->pc & 0xffff;

			break;
	}
}

static void sp_run(llsim_unit_t *unit)
{
	sp_t *sp = (sp_t *) unit->private;

	if (llsim->reset) {
		sp_reset(sp);
		return;
	}

	sp->sram->read = 0;
	sp->sram->write = 0;

	sp_ctl(sp);
}

static void sp_generate_sram_memory_image(sp_t *sp, char *program_name)
{
	FILE *fp;
	int addr, i;

	fp = fopen(program_name, "r");
	if (fp == NULL) {
		printf("couldn't open file %s\n", program_name);
		exit(1);
	}
	addr = 0;
	while (addr < SP_SRAM_HEIGHT) {
		fscanf(fp, "%08x\n", &sp->memory_image[addr]);
		addr++;
		if (feof(fp))
			break;
	}
	sp->memory_image_size = addr;

	fprintf(inst_trace_fp, "program %s loaded, %d lines\n", program_name);

	for (i = 0; i < sp->memory_image_size; i++)
		llsim_mem_inject(sp->sram, i, sp->memory_image[i], 31, 0);
}

static void sp_register_all_registers(sp_t *sp)
{
	sp_registers_t *spro = sp->spro, *sprn = sp->sprn;

	// registers
	llsim_register_register("sp", "r_0", 32, 0, &spro->r[0], &sprn->r[0]);
	llsim_register_register("sp", "r_1", 32, 0, &spro->r[1], &sprn->r[1]);
	llsim_register_register("sp", "r_2", 32, 0, &spro->r[2], &sprn->r[2]);
	llsim_register_register("sp", "r_3", 32, 0, &spro->r[3], &sprn->r[3]);
	llsim_register_register("sp", "r_4", 32, 0, &spro->r[4], &sprn->r[4]);
	llsim_register_register("sp", "r_5", 32, 0, &spro->r[5], &sprn->r[5]);
	llsim_register_register("sp", "r_6", 32, 0, &spro->r[6], &sprn->r[6]);
	llsim_register_register("sp", "r_7", 32, 0, &spro->r[7], &sprn->r[7]);

	llsim_register_register("sp", "pc", 16, 0, &spro->pc, &sprn->pc);
	llsim_register_register("sp", "inst", 32, 0, &spro->inst, &sprn->inst);
	llsim_register_register("sp", "opcode", 5, 0, &spro->opcode, &sprn->opc
	llsim_register_register("sp", "dst", 3, 0, &spro->dst, &sprn->dst);
	llsim_register_register("sp", "src0", 3, 0, &spro->src0, &sprn->src0);
	llsim_register_register("sp", "src1", 3, 0, &spro->src1, &sprn->src1);
	llsim_register_register("sp", "alu0", 32, 0, &spro->alu0, &sprn->alu0);
}

void sp_init(char *program_name)
{
	llsim_unit_t *llsim_sp_unit;
	llsim_unit_registers_t *llsim_ur;
	sp_t *sp;

	llsim_printf("initializing sp unit\n");

	inst_trace_fp = fopen("inst_trace.txt", "w");
	if (inst_trace_fp == NULL) {
		printf("couldn't open file inst_trace.txt\n");
		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);
}

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

#include "llsim.h"




		do {							\
			llsim_printf("sp: clock %d: ", llsim->clock);	\
			llsim_printf(a);				\
		} while (0)

int nr_simulated_instructions = 0;
FILE *inst_trace_fp = NULL, *cycle_trace_fp = NULL;


typedef struct sp_registers_s {
	// 6 32 bit registers (r[0], r[1] don't exist)
	int r[8];

	// 16 bit program counter
	int pc;

	// 32 bit instruction
	int inst;

	// 5 bit opcode
	int opcode;

	// 3 bit destination register index
	int dst;

	// 3 bit source #0 register index
	int src0;

	// 3 bit source #1 register index
	int src1;

	// 32 bit alu #0 operand
	int alu0;

	// 32 bit alu #1 operand
	int alu1;

	// 32 bit alu output
	int aluout;

	// 32 bit immediate field (original 16 bit sign extended)
	int immediate;

	// 32 bit cycle counter
	int cycle_counter;

	// 3 bit control state machine state register
	int ctl_state;

	// control states







} sp_registers_t;

/*
 * Master structure
 */
typedef struct sp_s {
	// local sram

	llsim_memory_t *sram;

	unsigned int memory_image[SP_SRAM_HEIGHT];
	int memory_image_size;

	sp_registers_t *spro, *sprn;
	int instruction_count;
	int start;
} sp_t;

static void sp_reset(sp_t *sp)
{
	sp_registers_t *sprn = sp->sprn;

	memset(sprn, 0, sizeof(*sprn));
}

/*
 * opcodes
 */

















static char opcode_name[32][4] = {"ADD", "SUB", "LSF", "RSF", "AND", "OR"
		"LD", "ST", "U", "U", "U", "U", "U", "U",
		"JLT", "JLE", "JEQ", "JNE", "JIN", "U", "U", "U",
		"HLT", "U", "U", "U", "U", "U", "U", "U"};

static void dump_sram(sp_t *sp)
{
	FILE *fp;
	int i;

	fp = fopen("sram_out.txt", "w");
	if (fp == NULL) {
		printf("couldn't open file sram_out.txt\n");
		exit(1);
	}
	for (i = 0; i < SP_SRAM_HEIGHT; i++)
		fprintf(fp, "%08x\n", llsim_mem_extract(sp->sram, i, 31, 0));
	fclose(fp);
}


static void sp_ctl(sp_t *sp)
{
	sp_registers_t *spro = sp->spro;
	sp_registers_t *sprn = sp->sprn;
	int i;
	char traceExecuteLine[100], traceExecuteLineContent[50],stringToP
	// sp_ctl

	fprintf(cycle_trace_fp, "cycle %d\n", spro->cycle_counter);
	for (i = 2; i <= 7; i++)
		fprintf(cycle_trace_fp, "r%d %08x\n", i, spro->r[i]);
	fprintf(cycle_trace_fp, "pc %08x\n", spro->pc);
	fprintf(cycle_trace_fp, "inst %08x\n", spro->inst);
	fprintf(cycle_trace_fp, "opcode %08x\n", spro->opcode);
	fprintf(cycle_trace_fp, "dst %08x\n", spro->dst);
	fprintf(cycle_trace_fp, "src0 %08x\n", spro->src0);
	fprintf(cycle_trace_fp, "src1 %08x\n", spro->src1);
	fprintf(cycle_trace_fp, "immediate %08x\n", spro->immediate);
	fprintf(cycle_trace_fp, "alu0 %08x\n", spro->alu0);
	fprintf(cycle_trace_fp, "alu1 %08x\n", spro->alu1);
	fprintf(cycle_trace_fp, "aluout %08x\n", spro->aluout);
	fprintf(cycle_trace_fp, "cycle_counter %08x\n", spro->cycle_counter);
	fprintf(cycle_trace_fp, "ctl_state %08x\n\n", spro->ctl_state);

	sprn->cycle_counter = spro->cycle_counter + 1;

	switch (spro->ctl_state) {
	case CTL_STATE_IDLE:
		sprn->pc = 0;
		sp->instruction_count = 0;
		if (sp->start)
			sprn->ctl_state = CTL_STATE_FETCH0;
		break;

	case CTL_STATE_FETCH0:
		llsim_mem_read(sp->sram, spro->pc);
		sprn->ctl_state = CTL_STATE_FETCH1;
		break;

	case CTL_STATE_FETCH1:
		sprn->inst = llsim_mem_extract_dataout(sp->sram, 31, 0);
		sprn->ctl_state = CTL_STATE_DEC0;
		break;

	case CTL_STATE_DEC0:
		sprn->opcode = ((0x3e000000 & spro->inst) >> 25);
		sprn->dst = ((0x01c00000 & spro->inst) >> 22);
		sprn->src0 = ((0x00380000 & spro->inst) >> 19);
		sprn->src1 = ((0x00070000 & spro->inst) >> 16);
		sprn->immediate = (((0x0000ffff & spro->inst) << 16)>>16);
		sprn->ctl_state = CTL_STATE_DEC1;
		break;

	case CTL_STATE_DEC1:

		if (spro->src0==0)
			sprn->alu0 = 0;
		else if (spro->src0==1)
			sprn->alu0 = spro->immediate;
		else
			sprn->alu0 = spro->r[spro->src0];

		if (spro->src1==0)
			sprn->alu1 = 0;
		else if (spro->src1==1)
			sprn->alu1 = spro->immediate;
		else
			sprn->alu1 = spro->r[spro->src1];

		//Print the trace (not including the EXEC part)
		sprintf(stringToPrint,"\n--- instruction %d (%04x) @ PC %d (%04d)",
				sp->instruction_count, sp->instruction_count,
				spro->pc, spro->pc);
		sprintf(temp," ------------------------------------------------------
		strcat(stringToPrint,temp);
		sprintf(temp,"pc = %04d, inst = %08x, ", spro->pc, spro->inst);
		strcat(stringToPrint,temp);
		sprintf(temp,"opcode = %d (%s)", spro->opcode, opcode_name[spro->opcod
		strcat(stringToPrint,temp);
		sprintf(temp,", dst = %d, src0 = %d, ", spro->dst, spro->src0);
		strcat(stringToPrint,temp);
		sprintf(temp,"src1 = %d, immediate = %08x\n", spro->src1, spro->immedia
		strcat(stringToPrint,temp);
		int i,reg;
		for (i=0; i<8; i++)
		{
			if (i==0)
				reg = 0;
			else if (i==1)
				reg = spro->immediate;
			else
				reg = sprn->r[i];

			sprintf(temp,"r[%d] = %08x ", i, reg);
			strcat(stringToPrint,temp);
			if (!((i+1)%4))
				strcat(stringToPrint,"\n");
		}
		fprintf(inst_trace_fp,"%s",stringToPrint);


		sprn->ctl_state = CTL_STATE_EXEC0;

		break;

	case CTL_STATE_EXEC0:

		switch (spro->opcode)
		{

		case ADD:
			sprn->aluout = spro->alu0 + spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case SUB:
			sprn->aluout = spro->alu0 - spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LSF:
			sprn->aluout = spro->alu0 << spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case RSF:
			sprn->aluout = spro->alu0 >> spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case AND:
			sprn->aluout = spro->alu0 & spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case OR:
			sprn->aluout = spro->alu0 | spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case XOR:
			sprn->aluout = spro->alu0 ^ spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LHI:
			sprn->aluout = (spro->alu1 << 16) | (spro->alu0 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LD:
			llsim_mem_read(sp->sram, spro->alu1 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case ST:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLT:
			sprn->aluout = spro->alu0 < spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLE:
			sprn->aluout = spro->alu0 <= spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JEQ:
			sprn->aluout =  spro->alu0 == spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JNE:
			sprn->aluout = spro->alu0 != spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JIN:
		case HLT:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;
		default:
			// Invalid OPCODE, go to fetch0
			sprn->pc = (spro->pc + 1) & 0xffff;
			sprn->ctl_state = CTL_STATE_FETCH0;
			break;
		}
		break;


				fprintf(inst_trace_fp,"%s",traceExecuteLine);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				break;
			}

			switch (spro->opcode)
			{

			case ADD:
			case SUB:
			case LSF:
			case RSF:
			case AND:
			case OR:
			case XOR:
			case LHI:
				sprn->r[spro->dst] = spro->aluout;
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						TRACE_EXEC_ARITH_CONTENT_LINE_PATTERN,
				break;

			case LD:
				sprn->r[spro->dst] = llsim_mem_extract_dataout(sp->sram, 31,
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"R[%d] = MEM[%d] = %08x ",
						spro->dst, spro->alu1,
						sprn->r[spro->dst]);
				break;

			case ST:
				llsim_mem_set_datain(sp->sram, spro->alu0, 31, 0);
				llsim_mem_write(sp->sram, spro->alu1 & 0xffff);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"MEM[%d] = R[%d] = %08x ",
						spro->alu1, spro->src0, spro->alu0);
				break;

			case JLT:
			case JLE:
			case JEQ:
			case JNE:
				if (spro->aluout){
					sprn->r[7] = spro->pc;
					sprn->pc = spro->immediate;
				}else
					sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ",opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case JIN:
				sprn->r[7] = spro->pc;
				sprn->pc = spro->alu0;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ", opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case HLT:
				sprn->ctl_state = CTL_STATE_IDLE;
				sprintf(traceExecuteLineContent,
						"HALT at PC %04x", spro->pc);
				llsim_stop();
				dump_sram(sp);
				break;

			default:
				// Invalid OPCODE, go to fetch0
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				traceExecuteLineContent[0]=0;
				break;
			}

			//Print the execution line to trace
			sprintf(traceExecuteLine, TRACE_EXEC_LINE_PATTERN, traceExecuteLin
            intf(inst_trace_fp,"%s",traceExecuteLine);
			sp->instruction_count = sp->instruction_count+1;

			//Print the final line to trace
			if (spro->opcode==HLT){
				char stringToPrint[100];
				sprintf(stringToPrint,"sim finished at pc %d, %d instructi
                ons",spro->pc,sp->instruction_count);
				fprintf(inst_trace_fp,"%s",stringToPrint);
				fclose(inst_trace_fp);
			}

			sprn->pc = sprn->pc & 0xffff;

			break;
	}
}

static void sp_run(llsim_unit_t *unit)
{
	sp_t *sp = (sp_t *) unit->private;

	if (llsim->reset) {
		sp_reset(sp);
		return;
	}

	sp->sram->read = 0;
	sp->sram->write = 0;

	sp_ctl(sp);
}

static void sp_generate_sram_memory_image(sp_t *sp, char *program_name)
{
	FILE *fp;
	int addr, i;

	fp = fopen(program_name, "r");
	if (fp == NULL) {
		printf("couldn't open file %s\n", program_name);
		exit(1);
	}
	addr = 0;
	while (addr < SP_SRAM_HEIGHT) {
		fscanf(fp, "%08x\n", &sp->memory_image[addr]);
		addr++;
		if (feof(fp))
			break;
	}
	sp->memory_image_size = addr;

	fprintf(inst_trace_fp, "program %s loaded, %d lines\n", program_name);

	for (i = 0; i < sp->memory_image_size; i++)
		llsim_mem_inject(sp->sram, i, sp->memory_image[i], 31, 0);
}

static void sp_register_all_registers(sp_t *sp)
{
	sp_registers_t *spro = sp->spro, *sprn = sp->sprn;

	// registers
	llsim_register_register("sp", "r_0", 32, 0, &spro->r[0], &sprn->r[0]);
	llsim_register_register("sp", "r_1", 32, 0, &spro->r[1], &sprn->r[1]);
	llsim_register_register("sp", "r_2", 32, 0, &spro->r[2], &sprn->r[2]);
	llsim_register_register("sp", "r_3", 32, 0, &spro->r[3], &sprn->r[3]);
	llsim_register_register("sp", "r_4", 32, 0, &spro->r[4], &sprn->r[4]);
	llsim_register_register("sp", "r_5", 32, 0, &spro->r[5], &sprn->r[5]);
	llsim_register_register("sp", "r_6", 32, 0, &spro->r[6], &sprn->r[6]);
	llsim_register_register("sp", "r_7", 32, 0, &spro->r[7], &sprn->r[7]);

	llsim_register_register("sp", "pc", 16, 0, &spro->pc, &sprn->pc);
	llsim_register_register("sp", "inst", 32, 0, &spro->inst, &sprn->inst);
	llsim_register_register("sp", "opcode", 5, 0, &spro->opcode, &sprn->opc
	llsim_register_register("sp", "dst", 3, 0, &spro->dst, &sprn->dst);
	llsim_register_register("sp", "src0", 3, 0, &spro->src0, &sprn->src0);
	llsim_register_register("sp", "src1", 3, 0, &spro->src1, &sprn->src1);
	llsim_register_register("sp", "alu0", 32, 0, &spro->alu0, &sprn->alu0);
}

void sp_init(char *program_name)
{
	llsim_unit_t *llsim_sp_unit;
	llsim_unit_registers_t *llsim_ur;
	sp_t *sp;

	llsim_printf("initializing sp unit\n");

	inst_trace_fp = fopen("inst_trace.txt", "w");
	if (inst_trace_fp == NULL) {
		printf("couldn't open file inst_trace.txt\n");
		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);
}

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

#include "llsim.h"




		do {							\
			llsim_printf("sp: clock %d: ", llsim->clock);	\
			llsim_printf(a);				\
		} while (0)

int nr_simulated_instructions = 0;
FILE *inst_trace_fp = NULL, *cycle_trace_fp = NULL;


typedef struct sp_registers_s {
	// 6 32 bit registers (r[0], r[1] don't exist)
	int r[8];

	// 16 bit program counter
	int pc;

	// 32 bit instruction
	int inst;

	// 5 bit opcode
	int opcode;

	// 3 bit destination register index
	int dst;

	// 3 bit source #0 register index
	int src0;

	// 3 bit source #1 register index
	int src1;

	// 32 bit alu #0 operand
	int alu0;

	// 32 bit alu #1 operand
	int alu1;

	// 32 bit alu output
	int aluout;

	// 32 bit immediate field (original 16 bit sign extended)
	int immediate;

	// 32 bit cycle counter
	int cycle_counter;

	// 3 bit control state machine state register
	int ctl_state;

	// control states







} sp_registers_t;

/*
 * Master structure
 */
typedef struct sp_s {
	// local sram

	llsim_memory_t *sram;

	unsigned int memory_image[SP_SRAM_HEIGHT];
	int memory_image_size;

	sp_registers_t *spro, *sprn;
	int instruction_count;
	int start;
} sp_t;

static void sp_reset(sp_t *sp)
{
	sp_registers_t *sprn = sp->sprn;

	memset(sprn, 0, sizeof(*sprn));
}

/*
 * opcodes
 */

















static char opcode_name[32][4] = {"ADD", "SUB", "LSF", "RSF", "AND", "OR"
		"LD", "ST", "U", "U", "U", "U", "U", "U",
		"JLT", "JLE", "JEQ", "JNE", "JIN", "U", "U", "U",
		"HLT", "U", "U", "U", "U", "U", "U", "U"};

static void dump_sram(sp_t *sp)
{
	FILE *fp;
	int i;

	fp = fopen("sram_out.txt", "w");
	if (fp == NULL) {
		printf("couldn't open file sram_out.txt\n");
		exit(1);
	}
	for (i = 0; i < SP_SRAM_HEIGHT; i++)
		fprintf(fp, "%08x\n", llsim_mem_extract(sp->sram, i, 31, 0));
	fclose(fp);
}


static void sp_ctl(sp_t *sp)
{
	sp_registers_t *spro = sp->spro;
	sp_registers_t *sprn = sp->sprn;
	int i;
	char traceExecuteLine[100], traceExecuteLineContent[50],stringToP
	// sp_ctl

	fprintf(cycle_trace_fp, "cycle %d\n", spro->cycle_counter);
	for (i = 2; i <= 7; i++)
		fprintf(cycle_trace_fp, "r%d %08x\n", i, spro->r[i]);
	fprintf(cycle_trace_fp, "pc %08x\n", spro->pc);
	fprintf(cycle_trace_fp, "inst %08x\n", spro->inst);
	fprintf(cycle_trace_fp, "opcode %08x\n", spro->opcode);
	fprintf(cycle_trace_fp, "dst %08x\n", spro->dst);
	fprintf(cycle_trace_fp, "src0 %08x\n", spro->src0);
	fprintf(cycle_trace_fp, "src1 %08x\n", spro->src1);
	fprintf(cycle_trace_fp, "immediate %08x\n", spro->immediate);
	fprintf(cycle_trace_fp, "alu0 %08x\n", spro->alu0);
	fprintf(cycle_trace_fp, "alu1 %08x\n", spro->alu1);
	fprintf(cycle_trace_fp, "aluout %08x\n", spro->aluout);
	fprintf(cycle_trace_fp, "cycle_counter %08x\n", spro->cycle_counter);
	fprintf(cycle_trace_fp, "ctl_state %08x\n\n", spro->ctl_state);

	sprn->cycle_counter = spro->cycle_counter + 1;

	switch (spro->ctl_state) {
	case CTL_STATE_IDLE:
		sprn->pc = 0;
		sp->instruction_count = 0;
		if (sp->start)
			sprn->ctl_state = CTL_STATE_FETCH0;
		break;

	case CTL_STATE_FETCH0:
		llsim_mem_read(sp->sram, spro->pc);
		sprn->ctl_state = CTL_STATE_FETCH1;
		break;

	case CTL_STATE_FETCH1:
		sprn->inst = llsim_mem_extract_dataout(sp->sram, 31, 0);
		sprn->ctl_state = CTL_STATE_DEC0;
		break;

	case CTL_STATE_DEC0:
		sprn->opcode = ((0x3e000000 & spro->inst) >> 25);
		sprn->dst = ((0x01c00000 & spro->inst) >> 22);
		sprn->src0 = ((0x00380000 & spro->inst) >> 19);
		sprn->src1 = ((0x00070000 & spro->inst) >> 16);
		sprn->immediate = (((0x0000ffff & spro->inst) << 16)>>16);
		sprn->ctl_state = CTL_STATE_DEC1;
		break;

	case CTL_STATE_DEC1:

		if (spro->src0==0)
			sprn->alu0 = 0;
		else if (spro->src0==1)
			sprn->alu0 = spro->immediate;
		else
			sprn->alu0 = spro->r[spro->src0];

		if (spro->src1==0)
			sprn->alu1 = 0;
		else if (spro->src1==1)
			sprn->alu1 = spro->immediate;
		else
			sprn->alu1 = spro->r[spro->src1];

		//Print the trace (not including the EXEC part)
		sprintf(stringToPrint,"\n--- instruction %d (%04x) @ PC %d (%04d)",
				sp->instruction_count, sp->instruction_count,
				spro->pc, spro->pc);
		sprintf(temp," ------------------------------------------------------
		strcat(stringToPrint,temp);
		sprintf(temp,"pc = %04d, inst = %08x, ", spro->pc, spro->inst);
		strcat(stringToPrint,temp);
		sprintf(temp,"opcode = %d (%s)", spro->opcode, opcode_name[spro->opcod
		strcat(stringToPrint,temp);
		sprintf(temp,", dst = %d, src0 = %d, ", spro->dst, spro->src0);
		strcat(stringToPrint,temp);
		sprintf(temp,"src1 = %d, immediate = %08x\n", spro->src1, spro->immedia
		strcat(stringToPrint,temp);
		int i,reg;
		for (i=0; i<8; i++)
		{
			if (i==0)
				reg = 0;
			else if (i==1)
				reg = spro->immediate;
			else
				reg = sprn->r[i];

			sprintf(temp,"r[%d] = %08x ", i, reg);
			strcat(stringToPrint,temp);
			if (!((i+1)%4))
				strcat(stringToPrint,"\n");
		}
		fprintf(inst_trace_fp,"%s",stringToPrint);


		sprn->ctl_state = CTL_STATE_EXEC0;

		break;

	case CTL_STATE_EXEC0:

		switch (spro->opcode)
		{

		case ADD:
			sprn->aluout = spro->alu0 + spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case SUB:
			sprn->aluout = spro->alu0 - spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LSF:
			sprn->aluout = spro->alu0 << spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case RSF:
			sprn->aluout = spro->alu0 >> spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case AND:
			sprn->aluout = spro->alu0 & spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case OR:
			sprn->aluout = spro->alu0 | spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case XOR:
			sprn->aluout = spro->alu0 ^ spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LHI:
			sprn->aluout = (spro->alu1 << 16) | (spro->alu0 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LD:
			llsim_mem_read(sp->sram, spro->alu1 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case ST:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLT:
			sprn->aluout = spro->alu0 < spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLE:
			sprn->aluout = spro->alu0 <= spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JEQ:
			sprn->aluout =  spro->alu0 == spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JNE:
			sprn->aluout = spro->alu0 != spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JIN:
		case HLT:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;
		default:
			// Invalid OPCODE, go to fetch0
			sprn->pc = (spro->pc + 1) & 0xffff;
			sprn->ctl_state = CTL_STATE_FETCH0;
			break;
		}
		break;


				fprintf(inst_trace_fp,"%s",traceExecuteLine);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				break;
			}

			switch (spro->opcode)
			{

			case ADD:
			case SUB:
			case LSF:
			case RSF:
			case AND:
			case OR:
			case XOR:
			case LHI:
				sprn->r[spro->dst] = spro->aluout;
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						TRACE_EXEC_ARITH_CONTENT_LINE_PATTERN,
				break;

			case LD:
				sprn->r[spro->dst] = llsim_mem_extract_dataout(sp->sram, 31,
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"R[%d] = MEM[%d] = %08x ",
						spro->dst, spro->alu1,
						sprn->r[spro->dst]);
				break;

			case ST:
				llsim_mem_set_datain(sp->sram, spro->alu0, 31, 0);
				llsim_mem_write(sp->sram, spro->alu1 & 0xffff);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"MEM[%d] = R[%d] = %08x ",
						spro->alu1, spro->src0, spro->alu0);
				break;

			case JLT:
			case JLE:
			case JEQ:
			case JNE:
				if (spro->aluout){
					sprn->r[7] = spro->pc;
					sprn->pc = spro->immediate;
				}else
					sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ",opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case JIN:
				sprn->r[7] = spro->pc;
				sprn->pc = spro->alu0;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ", opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case HLT:
				sprn->ctl_state = CTL_STATE_IDLE;
				sprintf(traceExecuteLineContent,
						"HALT at PC %04x", spro->pc);
				llsim_stop();
				dump_sram(sp);
				break;

			default:
				// Invalid OPCODE, go to fetch0
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				traceExecuteLineContent[0]=0;
				break;
			}

			//Print the execution line to trace
			sprintf(traceExecuteLine, TRACE_EXEC_LINE_PATTERN, traceExecuteLin
            intf(inst_trace_fp,"%s",traceExecuteLine);
			sp->instruction_count = sp->instruction_count+1;

			//Print the final line to trace
			if (spro->opcode==HLT){
				char stringToPrint[100];
				sprintf(stringToPrint,"sim finished at pc %d, %d instructi
                ons",spro->pc,sp->instruction_count);
				fprintf(inst_trace_fp,"%s",stringToPrint);
				fclose(inst_trace_fp);
			}

			sprn->pc = sprn->pc & 0xffff;

			break;
	}
}

static void sp_run(llsim_unit_t *unit)
{
	sp_t *sp = (sp_t *) unit->private;

	if (llsim->reset) {
		sp_reset(sp);
		return;
	}

	sp->sram->read = 0;
	sp->sram->write = 0;

	sp_ctl(sp);
}

static void sp_generate_sram_memory_image(sp_t *sp, char *program_name)
{
	FILE *fp;
	int addr, i;

	fp = fopen(program_name, "r");
	if (fp == NULL) {
		printf("couldn't open file %s\n", program_name);
		exit(1);
	}
	addr = 0;
	while (addr < SP_SRAM_HEIGHT) {
		fscanf(fp, "%08x\n", &sp->memory_image[addr]);
		addr++;
		if (feof(fp))
			break;
	}
	sp->memory_image_size = addr;

	fprintf(inst_trace_fp, "program %s loaded, %d lines\n", program_name);

	for (i = 0; i < sp->memory_image_size; i++)
		llsim_mem_inject(sp->sram, i, sp->memory_image[i], 31, 0);
}

static void sp_register_all_registers(sp_t *sp)
{
	sp_registers_t *spro = sp->spro, *sprn = sp->sprn;

	// registers
	llsim_register_register("sp", "r_0", 32, 0, &spro->r[0], &sprn->r[0]);
	llsim_register_register("sp", "r_1", 32, 0, &spro->r[1], &sprn->r[1]);
	llsim_register_register("sp", "r_2", 32, 0, &spro->r[2], &sprn->r[2]);
	llsim_register_register("sp", "r_3", 32, 0, &spro->r[3], &sprn->r[3]);
	llsim_register_register("sp", "r_4", 32, 0, &spro->r[4], &sprn->r[4]);
	llsim_register_register("sp", "r_5", 32, 0, &spro->r[5], &sprn->r[5]);
	llsim_register_register("sp", "r_6", 32, 0, &spro->r[6], &sprn->r[6]);
	llsim_register_register("sp", "r_7", 32, 0, &spro->r[7], &sprn->r[7]);

	llsim_register_register("sp", "pc", 16, 0, &spro->pc, &sprn->pc);
	llsim_register_register("sp", "inst", 32, 0, &spro->inst, &sprn->inst);
	llsim_register_register("sp", "opcode", 5, 0, &spro->opcode, &sprn->opc
	llsim_register_register("sp", "dst", 3, 0, &spro->dst, &sprn->dst);
	llsim_register_register("sp", "src0", 3, 0, &spro->src0, &sprn->src0);
	llsim_register_register("sp", "src1", 3, 0, &spro->src1, &sprn->src1);
	llsim_register_register("sp", "alu0", 32, 0, &spro->alu0, &sprn->alu0);
}

void sp_init(char *program_name)
{
	llsim_unit_t *llsim_sp_unit;
	llsim_unit_registers_t *llsim_ur;
	sp_t *sp;

	llsim_printf("initializing sp unit\n");

	inst_trace_fp = fopen("inst_trace.txt", "w");
	if (inst_trace_fp == NULL) {
		printf("couldn't open file inst_trace.txt\n");
		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);
}

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

#include "llsim.h"




		do {							\
			llsim_printf("sp: clock %d: ", llsim->clock);	\
			llsim_printf(a);				\
		} while (0)

int nr_simulated_instructions = 0;
FILE *inst_trace_fp = NULL, *cycle_trace_fp = NULL;


typedef struct sp_registers_s {
	// 6 32 bit registers (r[0], r[1] don't exist)
	int r[8];

	// 16 bit program counter
	int pc;

	// 32 bit instruction
	int inst;

	// 5 bit opcode
	int opcode;

	// 3 bit destination register index
	int dst;

	// 3 bit source #0 register index
	int src0;

	// 3 bit source #1 register index
	int src1;

	// 32 bit alu #0 operand
	int alu0;

	// 32 bit alu #1 operand
	int alu1;

	// 32 bit alu output
	int aluout;

	// 32 bit immediate field (original 16 bit sign extended)
	int immediate;

	// 32 bit cycle counter
	int cycle_counter;

	// 3 bit control state machine state register
	int ctl_state;

	// control states







} sp_registers_t;

/*
 * Master structure
 */
typedef struct sp_s {
	// local sram

	llsim_memory_t *sram;

	unsigned int memory_image[SP_SRAM_HEIGHT];
	int memory_image_size;

	sp_registers_t *spro, *sprn;
	int instruction_count;
	int start;
} sp_t;

static void sp_reset(sp_t *sp)
{
	sp_registers_t *sprn = sp->sprn;

	memset(sprn, 0, sizeof(*sprn));
}

/*
 * opcodes
 */

















static char opcode_name[32][4] = {"ADD", "SUB", "LSF", "RSF", "AND", "OR"
		"LD", "ST", "U", "U", "U", "U", "U", "U",
		"JLT", "JLE", "JEQ", "JNE", "JIN", "U", "U", "U",
		"HLT", "U", "U", "U", "U", "U", "U", "U"};

static void dump_sram(sp_t *sp)
{
	FILE *fp;
	int i;

	fp = fopen("sram_out.txt", "w");
	if (fp == NULL) {
		printf("couldn't open file sram_out.txt\n");
		exit(1);
	}
	for (i = 0; i < SP_SRAM_HEIGHT; i++)
		fprintf(fp, "%08x\n", llsim_mem_extract(sp->sram, i, 31, 0));
	fclose(fp);
}


static void sp_ctl(sp_t *sp)
{
	sp_registers_t *spro = sp->spro;
	sp_registers_t *sprn = sp->sprn;
	int i;
	char traceExecuteLine[100], traceExecuteLineContent[50],stringToP
	// sp_ctl

	fprintf(cycle_trace_fp, "cycle %d\n", spro->cycle_counter);
	for (i = 2; i <= 7; i++)
		fprintf(cycle_trace_fp, "r%d %08x\n", i, spro->r[i]);
	fprintf(cycle_trace_fp, "pc %08x\n", spro->pc);
	fprintf(cycle_trace_fp, "inst %08x\n", spro->inst);
	fprintf(cycle_trace_fp, "opcode %08x\n", spro->opcode);
	fprintf(cycle_trace_fp, "dst %08x\n", spro->dst);
	fprintf(cycle_trace_fp, "src0 %08x\n", spro->src0);
	fprintf(cycle_trace_fp, "src1 %08x\n", spro->src1);
	fprintf(cycle_trace_fp, "immediate %08x\n", spro->immediate);
	fprintf(cycle_trace_fp, "alu0 %08x\n", spro->alu0);
	fprintf(cycle_trace_fp, "alu1 %08x\n", spro->alu1);
	fprintf(cycle_trace_fp, "aluout %08x\n", spro->aluout);
	fprintf(cycle_trace_fp, "cycle_counter %08x\n", spro->cycle_counter);
	fprintf(cycle_trace_fp, "ctl_state %08x\n\n", spro->ctl_state);

	sprn->cycle_counter = spro->cycle_counter + 1;

	switch (spro->ctl_state) {
	case CTL_STATE_IDLE:
		sprn->pc = 0;
		sp->instruction_count = 0;
		if (sp->start)
			sprn->ctl_state = CTL_STATE_FETCH0;
		break;

	case CTL_STATE_FETCH0:
		llsim_mem_read(sp->sram, spro->pc);
		sprn->ctl_state = CTL_STATE_FETCH1;
		break;

	case CTL_STATE_FETCH1:
		sprn->inst = llsim_mem_extract_dataout(sp->sram, 31, 0);
		sprn->ctl_state = CTL_STATE_DEC0;
		break;

	case CTL_STATE_DEC0:
		sprn->opcode = ((0x3e000000 & spro->inst) >> 25);
		sprn->dst = ((0x01c00000 & spro->inst) >> 22);
		sprn->src0 = ((0x00380000 & spro->inst) >> 19);
		sprn->src1 = ((0x00070000 & spro->inst) >> 16);
		sprn->immediate = (((0x0000ffff & spro->inst) << 16)>>16);
		sprn->ctl_state = CTL_STATE_DEC1;
		break;

	case CTL_STATE_DEC1:

		if (spro->src0==0)
			sprn->alu0 = 0;
		else if (spro->src0==1)
			sprn->alu0 = spro->immediate;
		else
			sprn->alu0 = spro->r[spro->src0];

		if (spro->src1==0)
			sprn->alu1 = 0;
		else if (spro->src1==1)
			sprn->alu1 = spro->immediate;
		else
			sprn->alu1 = spro->r[spro->src1];

		//Print the trace (not including the EXEC part)
		sprintf(stringToPrint,"\n--- instruction %d (%04x) @ PC %d (%04d)",
				sp->instruction_count, sp->instruction_count,
				spro->pc, spro->pc);
		sprintf(temp," ------------------------------------------------------
		strcat(stringToPrint,temp);
		sprintf(temp,"pc = %04d, inst = %08x, ", spro->pc, spro->inst);
		strcat(stringToPrint,temp);
		sprintf(temp,"opcode = %d (%s)", spro->opcode, opcode_name[spro->opcod
		strcat(stringToPrint,temp);
		sprintf(temp,", dst = %d, src0 = %d, ", spro->dst, spro->src0);
		strcat(stringToPrint,temp);
		sprintf(temp,"src1 = %d, immediate = %08x\n", spro->src1, spro->immedia
		strcat(stringToPrint,temp);
		int i,reg;
		for (i=0; i<8; i++)
		{
			if (i==0)
				reg = 0;
			else if (i==1)
				reg = spro->immediate;
			else
				reg = sprn->r[i];

			sprintf(temp,"r[%d] = %08x ", i, reg);
			strcat(stringToPrint,temp);
			if (!((i+1)%4))
				strcat(stringToPrint,"\n");
		}
		fprintf(inst_trace_fp,"%s",stringToPrint);


		sprn->ctl_state = CTL_STATE_EXEC0;

		break;

	case CTL_STATE_EXEC0:

		switch (spro->opcode)
		{

		case ADD:
			sprn->aluout = spro->alu0 + spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case SUB:
			sprn->aluout = spro->alu0 - spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LSF:
			sprn->aluout = spro->alu0 << spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case RSF:
			sprn->aluout = spro->alu0 >> spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case AND:
			sprn->aluout = spro->alu0 & spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case OR:
			sprn->aluout = spro->alu0 | spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case XOR:
			sprn->aluout = spro->alu0 ^ spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LHI:
			sprn->aluout = (spro->alu1 << 16) | (spro->alu0 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LD:
			llsim_mem_read(sp->sram, spro->alu1 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case ST:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLT:
			sprn->aluout = spro->alu0 < spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLE:
			sprn->aluout = spro->alu0 <= spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JEQ:
			sprn->aluout =  spro->alu0 == spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JNE:
			sprn->aluout = spro->alu0 != spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JIN:
		case HLT:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;
		default:
			// Invalid OPCODE, go to fetch0
			sprn->pc = (spro->pc + 1) & 0xffff;
			sprn->ctl_state = CTL_STATE_FETCH0;
			break;
		}
		break;


				fprintf(inst_trace_fp,"%s",traceExecuteLine);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				break;
			}

			switch (spro->opcode)
			{

			case ADD:
			case SUB:
			case LSF:
			case RSF:
			case AND:
			case OR:
			case XOR:
			case LHI:
				sprn->r[spro->dst] = spro->aluout;
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						TRACE_EXEC_ARITH_CONTENT_LINE_PATTERN,
				break;

			case LD:
				sprn->r[spro->dst] = llsim_mem_extract_dataout(sp->sram, 31,
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"R[%d] = MEM[%d] = %08x ",
						spro->dst, spro->alu1,
						sprn->r[spro->dst]);
				break;

			case ST:
				llsim_mem_set_datain(sp->sram, spro->alu0, 31, 0);
				llsim_mem_write(sp->sram, spro->alu1 & 0xffff);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"MEM[%d] = R[%d] = %08x ",
						spro->alu1, spro->src0, spro->alu0);
				break;

			case JLT:
			case JLE:
			case JEQ:
			case JNE:
				if (spro->aluout){
					sprn->r[7] = spro->pc;
					sprn->pc = spro->immediate;
				}else
					sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ",opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case JIN:
				sprn->r[7] = spro->pc;
				sprn->pc = spro->alu0;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ", opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case HLT:
				sprn->ctl_state = CTL_STATE_IDLE;
				sprintf(traceExecuteLineContent,
						"HALT at PC %04x", spro->pc);
				llsim_stop();
				dump_sram(sp);
				break;

			default:
				// Invalid OPCODE, go to fetch0
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				traceExecuteLineContent[0]=0;
				break;
			}

			//Print the execution line to trace
			sprintf(traceExecuteLine, TRACE_EXEC_LINE_PATTERN, traceExecuteLin
            intf(inst_trace_fp,"%s",traceExecuteLine);
			sp->instruction_count = sp->instruction_count+1;

			//Print the final line to trace
			if (spro->opcode==HLT){
				char stringToPrint[100];
				sprintf(stringToPrint,"sim finished at pc %d, %d instructi
                ons",spro->pc,sp->instruction_count);
				fprintf(inst_trace_fp,"%s",stringToPrint);
				fclose(inst_trace_fp);
			}

			sprn->pc = sprn->pc & 0xffff;

			break;
	}
}

static void sp_run(llsim_unit_t *unit)
{
	sp_t *sp = (sp_t *) unit->private;

	if (llsim->reset) {
		sp_reset(sp);
		return;
	}

	sp->sram->read = 0;
	sp->sram->write = 0;

	sp_ctl(sp);
}

static void sp_generate_sram_memory_image(sp_t *sp, char *program_name)
{
	FILE *fp;
	int addr, i;

	fp = fopen(program_name, "r");
	if (fp == NULL) {
		printf("couldn't open file %s\n", program_name);
		exit(1);
	}
	addr = 0;
	while (addr < SP_SRAM_HEIGHT) {
		fscanf(fp, "%08x\n", &sp->memory_image[addr]);
		addr++;
		if (feof(fp))
			break;
	}
	sp->memory_image_size = addr;

	fprintf(inst_trace_fp, "program %s loaded, %d lines\n", program_name);

	for (i = 0; i < sp->memory_image_size; i++)
		llsim_mem_inject(sp->sram, i, sp->memory_image[i], 31, 0);
}

static void sp_register_all_registers(sp_t *sp)
{
	sp_registers_t *spro = sp->spro, *sprn = sp->sprn;

	// registers
	llsim_register_register("sp", "r_0", 32, 0, &spro->r[0], &sprn->r[0]);
	llsim_register_register("sp", "r_1", 32, 0, &spro->r[1], &sprn->r[1]);
	llsim_register_register("sp", "r_2", 32, 0, &spro->r[2], &sprn->r[2]);
	llsim_register_register("sp", "r_3", 32, 0, &spro->r[3], &sprn->r[3]);
	llsim_register_register("sp", "r_4", 32, 0, &spro->r[4], &sprn->r[4]);
	llsim_register_register("sp", "r_5", 32, 0, &spro->r[5], &sprn->r[5]);
	llsim_register_register("sp", "r_6", 32, 0, &spro->r[6], &sprn->r[6]);
	llsim_register_register("sp", "r_7", 32, 0, &spro->r[7], &sprn->r[7]);

	llsim_register_register("sp", "pc", 16, 0, &spro->pc, &sprn->pc);
	llsim_register_register("sp", "inst", 32, 0, &spro->inst, &sprn->inst);
	llsim_register_register("sp", "opcode", 5, 0, &spro->opcode, &sprn->opc
	llsim_register_register("sp", "dst", 3, 0, &spro->dst, &sprn->dst);
	llsim_register_register("sp", "src0", 3, 0, &spro->src0, &sprn->src0);
	llsim_register_register("sp", "src1", 3, 0, &spro->src1, &sprn->src1);
	llsim_register_register("sp", "alu0", 32, 0, &spro->alu0, &sprn->alu0);
}

void sp_init(char *program_name)
{
	llsim_unit_t *llsim_sp_unit;
	llsim_unit_registers_t *llsim_ur;
	sp_t *sp;

	llsim_printf("initializing sp unit\n");

	inst_trace_fp = fopen("inst_trace.txt", "w");
	if (inst_trace_fp == NULL) {
		printf("couldn't open file inst_trace.txt\n");
		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);
}

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

#include "llsim.h"




		do {							\
			llsim_printf("sp: clock %d: ", llsim->clock);	\
			llsim_printf(a);				\
		} while (0)

int nr_simulated_instructions = 0;
FILE *inst_trace_fp = NULL, *cycle_trace_fp = NULL;


typedef struct sp_registers_s {
	// 6 32 bit registers (r[0], r[1] don't exist)
	int r[8];

	// 16 bit program counter
	int pc;

	// 32 bit instruction
	int inst;

	// 5 bit opcode
	int opcode;

	// 3 bit destination register index
	int dst;

	// 3 bit source #0 register index
	int src0;

	// 3 bit source #1 register index
	int src1;

	// 32 bit alu #0 operand
	int alu0;

	// 32 bit alu #1 operand
	int alu1;

	// 32 bit alu output
	int aluout;

	// 32 bit immediate field (original 16 bit sign extended)
	int immediate;

	// 32 bit cycle counter
	int cycle_counter;

	// 3 bit control state machine state register
	int ctl_state;

	// control states







} sp_registers_t;

/*
 * Master structure
 */
typedef struct sp_s {
	// local sram

	llsim_memory_t *sram;

	unsigned int memory_image[SP_SRAM_HEIGHT];
	int memory_image_size;

	sp_registers_t *spro, *sprn;
	int instruction_count;
	int start;
} sp_t;

static void sp_reset(sp_t *sp)
{
	sp_registers_t *sprn = sp->sprn;

	memset(sprn, 0, sizeof(*sprn));
}

/*
 * opcodes
 */

















static char opcode_name[32][4] = {"ADD", "SUB", "LSF", "RSF", "AND", "OR"
		"LD", "ST", "U", "U", "U", "U", "U", "U",
		"JLT", "JLE", "JEQ", "JNE", "JIN", "U", "U", "U",
		"HLT", "U", "U", "U", "U", "U", "U", "U"};

static void dump_sram(sp_t *sp)
{
	FILE *fp;
	int i;

	fp = fopen("sram_out.txt", "w");
	if (fp == NULL) {
		printf("couldn't open file sram_out.txt\n");
		exit(1);
	}
	for (i = 0; i < SP_SRAM_HEIGHT; i++)
		fprintf(fp, "%08x\n", llsim_mem_extract(sp->sram, i, 31, 0));
	fclose(fp);
}


static void sp_ctl(sp_t *sp)
{
	sp_registers_t *spro = sp->spro;
	sp_registers_t *sprn = sp->sprn;
	int i;
	char traceExecuteLine[100], traceExecuteLineContent[50],stringToP
	// sp_ctl

	fprintf(cycle_trace_fp, "cycle %d\n", spro->cycle_counter);
	for (i = 2; i <= 7; i++)
		fprintf(cycle_trace_fp, "r%d %08x\n", i, spro->r[i]);
	fprintf(cycle_trace_fp, "pc %08x\n", spro->pc);
	fprintf(cycle_trace_fp, "inst %08x\n", spro->inst);
	fprintf(cycle_trace_fp, "opcode %08x\n", spro->opcode);
	fprintf(cycle_trace_fp, "dst %08x\n", spro->dst);
	fprintf(cycle_trace_fp, "src0 %08x\n", spro->src0);
	fprintf(cycle_trace_fp, "src1 %08x\n", spro->src1);
	fprintf(cycle_trace_fp, "immediate %08x\n", spro->immediate);
	fprintf(cycle_trace_fp, "alu0 %08x\n", spro->alu0);
	fprintf(cycle_trace_fp, "alu1 %08x\n", spro->alu1);
	fprintf(cycle_trace_fp, "aluout %08x\n", spro->aluout);
	fprintf(cycle_trace_fp, "cycle_counter %08x\n", spro->cycle_counter);
	fprintf(cycle_trace_fp, "ctl_state %08x\n\n", spro->ctl_state);

	sprn->cycle_counter = spro->cycle_counter + 1;

	switch (spro->ctl_state) {
	case CTL_STATE_IDLE:
		sprn->pc = 0;
		sp->instruction_count = 0;
		if (sp->start)
			sprn->ctl_state = CTL_STATE_FETCH0;
		break;

	case CTL_STATE_FETCH0:
		llsim_mem_read(sp->sram, spro->pc);
		sprn->ctl_state = CTL_STATE_FETCH1;
		break;

	case CTL_STATE_FETCH1:
		sprn->inst = llsim_mem_extract_dataout(sp->sram, 31, 0);
		sprn->ctl_state = CTL_STATE_DEC0;
		break;

	case CTL_STATE_DEC0:
		sprn->opcode = ((0x3e000000 & spro->inst) >> 25);
		sprn->dst = ((0x01c00000 & spro->inst) >> 22);
		sprn->src0 = ((0x00380000 & spro->inst) >> 19);
		sprn->src1 = ((0x00070000 & spro->inst) >> 16);
		sprn->immediate = (((0x0000ffff & spro->inst) << 16)>>16);
		sprn->ctl_state = CTL_STATE_DEC1;
		break;

	case CTL_STATE_DEC1:

		if (spro->src0==0)
			sprn->alu0 = 0;
		else if (spro->src0==1)
			sprn->alu0 = spro->immediate;
		else
			sprn->alu0 = spro->r[spro->src0];

		if (spro->src1==0)
			sprn->alu1 = 0;
		else if (spro->src1==1)
			sprn->alu1 = spro->immediate;
		else
			sprn->alu1 = spro->r[spro->src1];

		//Print the trace (not including the EXEC part)
		sprintf(stringToPrint,"\n--- instruction %d (%04x) @ PC %d (%04d)",
				sp->instruction_count, sp->instruction_count,
				spro->pc, spro->pc);
		sprintf(temp," ------------------------------------------------------
		strcat(stringToPrint,temp);
		sprintf(temp,"pc = %04d, inst = %08x, ", spro->pc, spro->inst);
		strcat(stringToPrint,temp);
		sprintf(temp,"opcode = %d (%s)", spro->opcode, opcode_name[spro->opcod
		strcat(stringToPrint,temp);
		sprintf(temp,", dst = %d, src0 = %d, ", spro->dst, spro->src0);
		strcat(stringToPrint,temp);
		sprintf(temp,"src1 = %d, immediate = %08x\n", spro->src1, spro->immedia
		strcat(stringToPrint,temp);
		int i,reg;
		for (i=0; i<8; i++)
		{
			if (i==0)
				reg = 0;
			else if (i==1)
				reg = spro->immediate;
			else
				reg = sprn->r[i];

			sprintf(temp,"r[%d] = %08x ", i, reg);
			strcat(stringToPrint,temp);
			if (!((i+1)%4))
				strcat(stringToPrint,"\n");
		}
		fprintf(inst_trace_fp,"%s",stringToPrint);


		sprn->ctl_state = CTL_STATE_EXEC0;

		break;

	case CTL_STATE_EXEC0:

		switch (spro->opcode)
		{

		case ADD:
			sprn->aluout = spro->alu0 + spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case SUB:
			sprn->aluout = spro->alu0 - spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LSF:
			sprn->aluout = spro->alu0 << spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case RSF:
			sprn->aluout = spro->alu0 >> spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case AND:
			sprn->aluout = spro->alu0 & spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case OR:
			sprn->aluout = spro->alu0 | spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case XOR:
			sprn->aluout = spro->alu0 ^ spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LHI:
			sprn->aluout = (spro->alu1 << 16) | (spro->alu0 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LD:
			llsim_mem_read(sp->sram, spro->alu1 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case ST:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLT:
			sprn->aluout = spro->alu0 < spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLE:
			sprn->aluout = spro->alu0 <= spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JEQ:
			sprn->aluout =  spro->alu0 == spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JNE:
			sprn->aluout = spro->alu0 != spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JIN:
		case HLT:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;
		default:
			// Invalid OPCODE, go to fetch0
			sprn->pc = (spro->pc + 1) & 0xffff;
			sprn->ctl_state = CTL_STATE_FETCH0;
			break;
		}
		break;


				fprintf(inst_trace_fp,"%s",traceExecuteLine);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				break;
			}

			switch (spro->opcode)
			{

			case ADD:
			case SUB:
			case LSF:
			case RSF:
			case AND:
			case OR:
			case XOR:
			case LHI:
				sprn->r[spro->dst] = spro->aluout;
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						TRACE_EXEC_ARITH_CONTENT_LINE_PATTERN,
				break;

			case LD:
				sprn->r[spro->dst] = llsim_mem_extract_dataout(sp->sram, 31,
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"R[%d] = MEM[%d] = %08x ",
						spro->dst, spro->alu1,
						sprn->r[spro->dst]);
				break;

			case ST:
				llsim_mem_set_datain(sp->sram, spro->alu0, 31, 0);
				llsim_mem_write(sp->sram, spro->alu1 & 0xffff);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"MEM[%d] = R[%d] = %08x ",
						spro->alu1, spro->src0, spro->alu0);
				break;

			case JLT:
			case JLE:
			case JEQ:
			case JNE:
				if (spro->aluout){
					sprn->r[7] = spro->pc;
					sprn->pc = spro->immediate;
				}else
					sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ",opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case JIN:
				sprn->r[7] = spro->pc;
				sprn->pc = spro->alu0;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ", opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case HLT:
				sprn->ctl_state = CTL_STATE_IDLE;
				sprintf(traceExecuteLineContent,
						"HALT at PC %04x", spro->pc);
				llsim_stop();
				dump_sram(sp);
				break;

			default:
				// Invalid OPCODE, go to fetch0
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				traceExecuteLineContent[0]=0;
				break;
			}

			//Print the execution line to trace
			sprintf(traceExecuteLine, TRACE_EXEC_LINE_PATTERN, traceExecuteLin
            intf(inst_trace_fp,"%s",traceExecuteLine);
			sp->instruction_count = sp->instruction_count+1;

			//Print the final line to trace
			if (spro->opcode==HLT){
				char stringToPrint[100];
				sprintf(stringToPrint,"sim finished at pc %d, %d instructi
                ons",spro->pc,sp->instruction_count);
				fprintf(inst_trace_fp,"%s",stringToPrint);
				fclose(inst_trace_fp);
			}

			sprn->pc = sprn->pc & 0xffff;

			break;
	}
}

static void sp_run(llsim_unit_t *unit)
{
	sp_t *sp = (sp_t *) unit->private;

	if (llsim->reset) {
		sp_reset(sp);
		return;
	}

	sp->sram->read = 0;
	sp->sram->write = 0;

	sp_ctl(sp);
}

static void sp_generate_sram_memory_image(sp_t *sp, char *program_name)
{
	FILE *fp;
	int addr, i;

	fp = fopen(program_name, "r");
	if (fp == NULL) {
		printf("couldn't open file %s\n", program_name);
		exit(1);
	}
	addr = 0;
	while (addr < SP_SRAM_HEIGHT) {
		fscanf(fp, "%08x\n", &sp->memory_image[addr]);
		addr++;
		if (feof(fp))
			break;
	}
	sp->memory_image_size = addr;

	fprintf(inst_trace_fp, "program %s loaded, %d lines\n", program_name);

	for (i = 0; i < sp->memory_image_size; i++)
		llsim_mem_inject(sp->sram, i, sp->memory_image[i], 31, 0);
}

static void sp_register_all_registers(sp_t *sp)
{
	sp_registers_t *spro = sp->spro, *sprn = sp->sprn;

	// registers
	llsim_register_register("sp", "r_0", 32, 0, &spro->r[0], &sprn->r[0]);
	llsim_register_register("sp", "r_1", 32, 0, &spro->r[1], &sprn->r[1]);
	llsim_register_register("sp", "r_2", 32, 0, &spro->r[2], &sprn->r[2]);
	llsim_register_register("sp", "r_3", 32, 0, &spro->r[3], &sprn->r[3]);
	llsim_register_register("sp", "r_4", 32, 0, &spro->r[4], &sprn->r[4]);
	llsim_register_register("sp", "r_5", 32, 0, &spro->r[5], &sprn->r[5]);
	llsim_register_register("sp", "r_6", 32, 0, &spro->r[6], &sprn->r[6]);
	llsim_register_register("sp", "r_7", 32, 0, &spro->r[7], &sprn->r[7]);

	llsim_register_register("sp", "pc", 16, 0, &spro->pc, &sprn->pc);
	llsim_register_register("sp", "inst", 32, 0, &spro->inst, &sprn->inst);
	llsim_register_register("sp", "opcode", 5, 0, &spro->opcode, &sprn->opc
	llsim_register_register("sp", "dst", 3, 0, &spro->dst, &sprn->dst);
	llsim_register_register("sp", "src0", 3, 0, &spro->src0, &sprn->src0);
	llsim_register_register("sp", "src1", 3, 0, &spro->src1, &sprn->src1);
	llsim_register_register("sp", "alu0", 32, 0, &spro->alu0, &sprn->alu0);
}

void sp_init(char *program_name)
{
	llsim_unit_t *llsim_sp_unit;
	llsim_unit_registers_t *llsim_ur;
	sp_t *sp;

	llsim_printf("initializing sp unit\n");

	inst_trace_fp = fopen("inst_trace.txt", "w");
	if (inst_trace_fp == NULL) {
		printf("couldn't open file inst_trace.txt\n");
		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);
}

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

#include "llsim.h"




		do {							\
			llsim_printf("sp: clock %d: ", llsim->clock);	\
			llsim_printf(a);				\
		} while (0)

int nr_simulated_instructions = 0;
FILE *inst_trace_fp = NULL, *cycle_trace_fp = NULL;


typedef struct sp_registers_s {
	// 6 32 bit registers (r[0], r[1] don't exist)
	int r[8];

	// 16 bit program counter
	int pc;

	// 32 bit instruction
	int inst;

	// 5 bit opcode
	int opcode;

	// 3 bit destination register index
	int dst;

	// 3 bit source #0 register index
	int src0;

	// 3 bit source #1 register index
	int src1;

	// 32 bit alu #0 operand
	int alu0;

	// 32 bit alu #1 operand
	int alu1;

	// 32 bit alu output
	int aluout;

	// 32 bit immediate field (original 16 bit sign extended)
	int immediate;

	// 32 bit cycle counter
	int cycle_counter;

	// 3 bit control state machine state register
	int ctl_state;

	// control states







} sp_registers_t;

/*
 * Master structure
 */
typedef struct sp_s {
	// local sram

	llsim_memory_t *sram;

	unsigned int memory_image[SP_SRAM_HEIGHT];
	int memory_image_size;

	sp_registers_t *spro, *sprn;
	int instruction_count;
	int start;
} sp_t;

static void sp_reset(sp_t *sp)
{
	sp_registers_t *sprn = sp->sprn;

	memset(sprn, 0, sizeof(*sprn));
}

/*
 * opcodes
 */

















static char opcode_name[32][4] = {"ADD", "SUB", "LSF", "RSF", "AND", "OR"
		"LD", "ST", "U", "U", "U", "U", "U", "U",
		"JLT", "JLE", "JEQ", "JNE", "JIN", "U", "U", "U",
		"HLT", "U", "U", "U", "U", "U", "U", "U"};

static void dump_sram(sp_t *sp)
{
	FILE *fp;
	int i;

	fp = fopen("sram_out.txt", "w");
	if (fp == NULL) {
		printf("couldn't open file sram_out.txt\n");
		exit(1);
	}
	for (i = 0; i < SP_SRAM_HEIGHT; i++)
		fprintf(fp, "%08x\n", llsim_mem_extract(sp->sram, i, 31, 0));
	fclose(fp);
}


static void sp_ctl(sp_t *sp)
{
	sp_registers_t *spro = sp->spro;
	sp_registers_t *sprn = sp->sprn;
	int i;
	char traceExecuteLine[100], traceExecuteLineContent[50],stringToP
	// sp_ctl

	fprintf(cycle_trace_fp, "cycle %d\n", spro->cycle_counter);
	for (i = 2; i <= 7; i++)
		fprintf(cycle_trace_fp, "r%d %08x\n", i, spro->r[i]);
	fprintf(cycle_trace_fp, "pc %08x\n", spro->pc);
	fprintf(cycle_trace_fp, "inst %08x\n", spro->inst);
	fprintf(cycle_trace_fp, "opcode %08x\n", spro->opcode);
	fprintf(cycle_trace_fp, "dst %08x\n", spro->dst);
	fprintf(cycle_trace_fp, "src0 %08x\n", spro->src0);
	fprintf(cycle_trace_fp, "src1 %08x\n", spro->src1);
	fprintf(cycle_trace_fp, "immediate %08x\n", spro->immediate);
	fprintf(cycle_trace_fp, "alu0 %08x\n", spro->alu0);
	fprintf(cycle_trace_fp, "alu1 %08x\n", spro->alu1);
	fprintf(cycle_trace_fp, "aluout %08x\n", spro->aluout);
	fprintf(cycle_trace_fp, "cycle_counter %08x\n", spro->cycle_counter);
	fprintf(cycle_trace_fp, "ctl_state %08x\n\n", spro->ctl_state);

	sprn->cycle_counter = spro->cycle_counter + 1;

	switch (spro->ctl_state) {
	case CTL_STATE_IDLE:
		sprn->pc = 0;
		sp->instruction_count = 0;
		if (sp->start)
			sprn->ctl_state = CTL_STATE_FETCH0;
		break;

	case CTL_STATE_FETCH0:
		llsim_mem_read(sp->sram, spro->pc);
		sprn->ctl_state = CTL_STATE_FETCH1;
		break;

	case CTL_STATE_FETCH1:
		sprn->inst = llsim_mem_extract_dataout(sp->sram, 31, 0);
		sprn->ctl_state = CTL_STATE_DEC0;
		break;

	case CTL_STATE_DEC0:
		sprn->opcode = ((0x3e000000 & spro->inst) >> 25);
		sprn->dst = ((0x01c00000 & spro->inst) >> 22);
		sprn->src0 = ((0x00380000 & spro->inst) >> 19);
		sprn->src1 = ((0x00070000 & spro->inst) >> 16);
		sprn->immediate = (((0x0000ffff & spro->inst) << 16)>>16);
		sprn->ctl_state = CTL_STATE_DEC1;
		break;

	case CTL_STATE_DEC1:

		if (spro->src0==0)
			sprn->alu0 = 0;
		else if (spro->src0==1)
			sprn->alu0 = spro->immediate;
		else
			sprn->alu0 = spro->r[spro->src0];

		if (spro->src1==0)
			sprn->alu1 = 0;
		else if (spro->src1==1)
			sprn->alu1 = spro->immediate;
		else
			sprn->alu1 = spro->r[spro->src1];

		//Print the trace (not including the EXEC part)
		sprintf(stringToPrint,"\n--- instruction %d (%04x) @ PC %d (%04d)",
				sp->instruction_count, sp->instruction_count,
				spro->pc, spro->pc);
		sprintf(temp," ------------------------------------------------------
		strcat(stringToPrint,temp);
		sprintf(temp,"pc = %04d, inst = %08x, ", spro->pc, spro->inst);
		strcat(stringToPrint,temp);
		sprintf(temp,"opcode = %d (%s)", spro->opcode, opcode_name[spro->opcod
		strcat(stringToPrint,temp);
		sprintf(temp,", dst = %d, src0 = %d, ", spro->dst, spro->src0);
		strcat(stringToPrint,temp);
		sprintf(temp,"src1 = %d, immediate = %08x\n", spro->src1, spro->immedia
		strcat(stringToPrint,temp);
		int i,reg;
		for (i=0; i<8; i++)
		{
			if (i==0)
				reg = 0;
			else if (i==1)
				reg = spro->immediate;
			else
				reg = sprn->r[i];

			sprintf(temp,"r[%d] = %08x ", i, reg);
			strcat(stringToPrint,temp);
			if (!((i+1)%4))
				strcat(stringToPrint,"\n");
		}
		fprintf(inst_trace_fp,"%s",stringToPrint);


		sprn->ctl_state = CTL_STATE_EXEC0;

		break;

	case CTL_STATE_EXEC0:

		switch (spro->opcode)
		{

		case ADD:
			sprn->aluout = spro->alu0 + spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case SUB:
			sprn->aluout = spro->alu0 - spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LSF:
			sprn->aluout = spro->alu0 << spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case RSF:
			sprn->aluout = spro->alu0 >> spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case AND:
			sprn->aluout = spro->alu0 & spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case OR:
			sprn->aluout = spro->alu0 | spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case XOR:
			sprn->aluout = spro->alu0 ^ spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LHI:
			sprn->aluout = (spro->alu1 << 16) | (spro->alu0 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LD:
			llsim_mem_read(sp->sram, spro->alu1 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case ST:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLT:
			sprn->aluout = spro->alu0 < spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLE:
			sprn->aluout = spro->alu0 <= spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JEQ:
			sprn->aluout =  spro->alu0 == spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JNE:
			sprn->aluout = spro->alu0 != spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JIN:
		case HLT:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;
		default:
			// Invalid OPCODE, go to fetch0
			sprn->pc = (spro->pc + 1) & 0xffff;
			sprn->ctl_state = CTL_STATE_FETCH0;
			break;
		}
		break;


				fprintf(inst_trace_fp,"%s",traceExecuteLine);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				break;
			}

			switch (spro->opcode)
			{

			case ADD:
			case SUB:
			case LSF:
			case RSF:
			case AND:
			case OR:
			case XOR:
			case LHI:
				sprn->r[spro->dst] = spro->aluout;
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						TRACE_EXEC_ARITH_CONTENT_LINE_PATTERN,
				break;

			case LD:
				sprn->r[spro->dst] = llsim_mem_extract_dataout(sp->sram, 31,
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"R[%d] = MEM[%d] = %08x ",
						spro->dst, spro->alu1,
						sprn->r[spro->dst]);
				break;

			case ST:
				llsim_mem_set_datain(sp->sram, spro->alu0, 31, 0);
				llsim_mem_write(sp->sram, spro->alu1 & 0xffff);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"MEM[%d] = R[%d] = %08x ",
						spro->alu1, spro->src0, spro->alu0);
				break;

			case JLT:
			case JLE:
			case JEQ:
			case JNE:
				if (spro->aluout){
					sprn->r[7] = spro->pc;
					sprn->pc = spro->immediate;
				}else
					sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ",opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case JIN:
				sprn->r[7] = spro->pc;
				sprn->pc = spro->alu0;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ", opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case HLT:
				sprn->ctl_state = CTL_STATE_IDLE;
				sprintf(traceExecuteLineContent,
						"HALT at PC %04x", spro->pc);
				llsim_stop();
				dump_sram(sp);
				break;

			default:
				// Invalid OPCODE, go to fetch0
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				traceExecuteLineContent[0]=0;
				break;
			}

			//Print the execution line to trace
			sprintf(traceExecuteLine, TRACE_EXEC_LINE_PATTERN, traceExecuteLin
            intf(inst_trace_fp,"%s",traceExecuteLine);
			sp->instruction_count = sp->instruction_count+1;

			//Print the final line to trace
			if (spro->opcode==HLT){
				char stringToPrint[100];
				sprintf(stringToPrint,"sim finished at pc %d, %d instructi
                ons",spro->pc,sp->instruction_count);
				fprintf(inst_trace_fp,"%s",stringToPrint);
				fclose(inst_trace_fp);
			}

			sprn->pc = sprn->pc & 0xffff;

			break;
	}
}

static void sp_run(llsim_unit_t *unit)
{
	sp_t *sp = (sp_t *) unit->private;

	if (llsim->reset) {
		sp_reset(sp);
		return;
	}

	sp->sram->read = 0;
	sp->sram->write = 0;

	sp_ctl(sp);
}

static void sp_generate_sram_memory_image(sp_t *sp, char *program_name)
{
	FILE *fp;
	int addr, i;

	fp = fopen(program_name, "r");
	if (fp == NULL) {
		printf("couldn't open file %s\n", program_name);
		exit(1);
	}
	addr = 0;
	while (addr < SP_SRAM_HEIGHT) {
		fscanf(fp, "%08x\n", &sp->memory_image[addr]);
		addr++;
		if (feof(fp))
			break;
	}
	sp->memory_image_size = addr;

	fprintf(inst_trace_fp, "program %s loaded, %d lines\n", program_name);

	for (i = 0; i < sp->memory_image_size; i++)
		llsim_mem_inject(sp->sram, i, sp->memory_image[i], 31, 0);
}

static void sp_register_all_registers(sp_t *sp)
{
	sp_registers_t *spro = sp->spro, *sprn = sp->sprn;

	// registers
	llsim_register_register("sp", "r_0", 32, 0, &spro->r[0], &sprn->r[0]);
	llsim_register_register("sp", "r_1", 32, 0, &spro->r[1], &sprn->r[1]);
	llsim_register_register("sp", "r_2", 32, 0, &spro->r[2], &sprn->r[2]);
	llsim_register_register("sp", "r_3", 32, 0, &spro->r[3], &sprn->r[3]);
	llsim_register_register("sp", "r_4", 32, 0, &spro->r[4], &sprn->r[4]);
	llsim_register_register("sp", "r_5", 32, 0, &spro->r[5], &sprn->r[5]);
	llsim_register_register("sp", "r_6", 32, 0, &spro->r[6], &sprn->r[6]);
	llsim_register_register("sp", "r_7", 32, 0, &spro->r[7], &sprn->r[7]);

	llsim_register_register("sp", "pc", 16, 0, &spro->pc, &sprn->pc);
	llsim_register_register("sp", "inst", 32, 0, &spro->inst, &sprn->inst);
	llsim_register_register("sp", "opcode", 5, 0, &spro->opcode, &sprn->opc
	llsim_register_register("sp", "dst", 3, 0, &spro->dst, &sprn->dst);
	llsim_register_register("sp", "src0", 3, 0, &spro->src0, &sprn->src0);
	llsim_register_register("sp", "src1", 3, 0, &spro->src1, &sprn->src1);
	llsim_register_register("sp", "alu0", 32, 0, &spro->alu0, &sprn->alu0);
}

void sp_init(char *program_name)
{
	llsim_unit_t *llsim_sp_unit;
	llsim_unit_registers_t *llsim_ur;
	sp_t *sp;

	llsim_printf("initializing sp unit\n");

	inst_trace_fp = fopen("inst_trace.txt", "w");
	if (inst_trace_fp == NULL) {
		printf("couldn't open file inst_trace.txt\n");
		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);
}

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

#include "llsim.h"




		do {							\
			llsim_printf("sp: clock %d: ", llsim->clock);	\
			llsim_printf(a);				\
		} while (0)

int nr_simulated_instructions = 0;
FILE *inst_trace_fp = NULL, *cycle_trace_fp = NULL;


typedef struct sp_registers_s {
	// 6 32 bit registers (r[0], r[1] don't exist)
	int r[8];

	// 16 bit program counter
	int pc;

	// 32 bit instruction
	int inst;

	// 5 bit opcode
	int opcode;

	// 3 bit destination register index
	int dst;

	// 3 bit source #0 register index
	int src0;

	// 3 bit source #1 register index
	int src1;

	// 32 bit alu #0 operand
	int alu0;

	// 32 bit alu #1 operand
	int alu1;

	// 32 bit alu output
	int aluout;

	// 32 bit immediate field (original 16 bit sign extended)
	int immediate;

	// 32 bit cycle counter
	int cycle_counter;

	// 3 bit control state machine state register
	int ctl_state;

	// control states







} sp_registers_t;

/*
 * Master structure
 */
typedef struct sp_s {
	// local sram

	llsim_memory_t *sram;

	unsigned int memory_image[SP_SRAM_HEIGHT];
	int memory_image_size;

	sp_registers_t *spro, *sprn;
	int instruction_count;
	int start;
} sp_t;

static void sp_reset(sp_t *sp)
{
	sp_registers_t *sprn = sp->sprn;

	memset(sprn, 0, sizeof(*sprn));
}

/*
 * opcodes
 */

















static char opcode_name[32][4] = {"ADD", "SUB", "LSF", "RSF", "AND", "OR"
		"LD", "ST", "U", "U", "U", "U", "U", "U",
		"JLT", "JLE", "JEQ", "JNE", "JIN", "U", "U", "U",
		"HLT", "U", "U", "U", "U", "U", "U", "U"};

static void dump_sram(sp_t *sp)
{
	FILE *fp;
	int i;

	fp = fopen("sram_out.txt", "w");
	if (fp == NULL) {
		printf("couldn't open file sram_out.txt\n");
		exit(1);
	}
	for (i = 0; i < SP_SRAM_HEIGHT; i++)
		fprintf(fp, "%08x\n", llsim_mem_extract(sp->sram, i, 31, 0));
	fclose(fp);
}


static void sp_ctl(sp_t *sp)
{
	sp_registers_t *spro = sp->spro;
	sp_registers_t *sprn = sp->sprn;
	int i;
	char traceExecuteLine[100], traceExecuteLineContent[50],stringToP
	// sp_ctl

	fprintf(cycle_trace_fp, "cycle %d\n", spro->cycle_counter);
	for (i = 2; i <= 7; i++)
		fprintf(cycle_trace_fp, "r%d %08x\n", i, spro->r[i]);
	fprintf(cycle_trace_fp, "pc %08x\n", spro->pc);
	fprintf(cycle_trace_fp, "inst %08x\n", spro->inst);
	fprintf(cycle_trace_fp, "opcode %08x\n", spro->opcode);
	fprintf(cycle_trace_fp, "dst %08x\n", spro->dst);
	fprintf(cycle_trace_fp, "src0 %08x\n", spro->src0);
	fprintf(cycle_trace_fp, "src1 %08x\n", spro->src1);
	fprintf(cycle_trace_fp, "immediate %08x\n", spro->immediate);
	fprintf(cycle_trace_fp, "alu0 %08x\n", spro->alu0);
	fprintf(cycle_trace_fp, "alu1 %08x\n", spro->alu1);
	fprintf(cycle_trace_fp, "aluout %08x\n", spro->aluout);
	fprintf(cycle_trace_fp, "cycle_counter %08x\n", spro->cycle_counter);
	fprintf(cycle_trace_fp, "ctl_state %08x\n\n", spro->ctl_state);

	sprn->cycle_counter = spro->cycle_counter + 1;

	switch (spro->ctl_state) {
	case CTL_STATE_IDLE:
		sprn->pc = 0;
		sp->instruction_count = 0;
		if (sp->start)
			sprn->ctl_state = CTL_STATE_FETCH0;
		break;

	case CTL_STATE_FETCH0:
		llsim_mem_read(sp->sram, spro->pc);
		sprn->ctl_state = CTL_STATE_FETCH1;
		break;

	case CTL_STATE_FETCH1:
		sprn->inst = llsim_mem_extract_dataout(sp->sram, 31, 0);
		sprn->ctl_state = CTL_STATE_DEC0;
		break;

	case CTL_STATE_DEC0:
		sprn->opcode = ((0x3e000000 & spro->inst) >> 25);
		sprn->dst = ((0x01c00000 & spro->inst) >> 22);
		sprn->src0 = ((0x00380000 & spro->inst) >> 19);
		sprn->src1 = ((0x00070000 & spro->inst) >> 16);
		sprn->immediate = (((0x0000ffff & spro->inst) << 16)>>16);
		sprn->ctl_state = CTL_STATE_DEC1;
		break;

	case CTL_STATE_DEC1:

		if (spro->src0==0)
			sprn->alu0 = 0;
		else if (spro->src0==1)
			sprn->alu0 = spro->immediate;
		else
			sprn->alu0 = spro->r[spro->src0];

		if (spro->src1==0)
			sprn->alu1 = 0;
		else if (spro->src1==1)
			sprn->alu1 = spro->immediate;
		else
			sprn->alu1 = spro->r[spro->src1];

		//Print the trace (not including the EXEC part)
		sprintf(stringToPrint,"\n--- instruction %d (%04x) @ PC %d (%04d)",
				sp->instruction_count, sp->instruction_count,
				spro->pc, spro->pc);
		sprintf(temp," ------------------------------------------------------
		strcat(stringToPrint,temp);
		sprintf(temp,"pc = %04d, inst = %08x, ", spro->pc, spro->inst);
		strcat(stringToPrint,temp);
		sprintf(temp,"opcode = %d (%s)", spro->opcode, opcode_name[spro->opcod
		strcat(stringToPrint,temp);
		sprintf(temp,", dst = %d, src0 = %d, ", spro->dst, spro->src0);
		strcat(stringToPrint,temp);
		sprintf(temp,"src1 = %d, immediate = %08x\n", spro->src1, spro->immedia
		strcat(stringToPrint,temp);
		int i,reg;
		for (i=0; i<8; i++)
		{
			if (i==0)
				reg = 0;
			else if (i==1)
				reg = spro->immediate;
			else
				reg = sprn->r[i];

			sprintf(temp,"r[%d] = %08x ", i, reg);
			strcat(stringToPrint,temp);
			if (!((i+1)%4))
				strcat(stringToPrint,"\n");
		}
		fprintf(inst_trace_fp,"%s",stringToPrint);


		sprn->ctl_state = CTL_STATE_EXEC0;

		break;

	case CTL_STATE_EXEC0:

		switch (spro->opcode)
		{

		case ADD:
			sprn->aluout = spro->alu0 + spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case SUB:
			sprn->aluout = spro->alu0 - spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LSF:
			sprn->aluout = spro->alu0 << spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case RSF:
			sprn->aluout = spro->alu0 >> spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case AND:
			sprn->aluout = spro->alu0 & spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case OR:
			sprn->aluout = spro->alu0 | spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case XOR:
			sprn->aluout = spro->alu0 ^ spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LHI:
			sprn->aluout = (spro->alu1 << 16) | (spro->alu0 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LD:
			llsim_mem_read(sp->sram, spro->alu1 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case ST:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLT:
			sprn->aluout = spro->alu0 < spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLE:
			sprn->aluout = spro->alu0 <= spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JEQ:
			sprn->aluout =  spro->alu0 == spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JNE:
			sprn->aluout = spro->alu0 != spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JIN:
		case HLT:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;
		default:
			// Invalid OPCODE, go to fetch0
			sprn->pc = (spro->pc + 1) & 0xffff;
			sprn->ctl_state = CTL_STATE_FETCH0;
			break;
		}
		break;


				fprintf(inst_trace_fp,"%s",traceExecuteLine);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				break;
			}

			switch (spro->opcode)
			{

			case ADD:
			case SUB:
			case LSF:
			case RSF:
			case AND:
			case OR:
			case XOR:
			case LHI:
				sprn->r[spro->dst] = spro->aluout;
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						TRACE_EXEC_ARITH_CONTENT_LINE_PATTERN,
				break;

			case LD:
				sprn->r[spro->dst] = llsim_mem_extract_dataout(sp->sram, 31,
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"R[%d] = MEM[%d] = %08x ",
						spro->dst, spro->alu1,
						sprn->r[spro->dst]);
				break;

			case ST:
				llsim_mem_set_datain(sp->sram, spro->alu0, 31, 0);
				llsim_mem_write(sp->sram, spro->alu1 & 0xffff);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"MEM[%d] = R[%d] = %08x ",
						spro->alu1, spro->src0, spro->alu0);
				break;

			case JLT:
			case JLE:
			case JEQ:
			case JNE:
				if (spro->aluout){
					sprn->r[7] = spro->pc;
					sprn->pc = spro->immediate;
				}else
					sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ",opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case JIN:
				sprn->r[7] = spro->pc;
				sprn->pc = spro->alu0;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ", opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case HLT:
				sprn->ctl_state = CTL_STATE_IDLE;
				sprintf(traceExecuteLineContent,
						"HALT at PC %04x", spro->pc);
				llsim_stop();
				dump_sram(sp);
				break;

			default:
				// Invalid OPCODE, go to fetch0
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				traceExecuteLineContent[0]=0;
				break;
			}

			//Print the execution line to trace
			sprintf(traceExecuteLine, TRACE_EXEC_LINE_PATTERN, traceExecuteLin
            intf(inst_trace_fp,"%s",traceExecuteLine);
			sp->instruction_count = sp->instruction_count+1;

			//Print the final line to trace
			if (spro->opcode==HLT){
				char stringToPrint[100];
				sprintf(stringToPrint,"sim finished at pc %d, %d instructi
                ons",spro->pc,sp->instruction_count);
				fprintf(inst_trace_fp,"%s",stringToPrint);
				fclose(inst_trace_fp);
			}

			sprn->pc = sprn->pc & 0xffff;

			break;
	}
}

static void sp_run(llsim_unit_t *unit)
{
	sp_t *sp = (sp_t *) unit->private;

	if (llsim->reset) {
		sp_reset(sp);
		return;
	}

	sp->sram->read = 0;
	sp->sram->write = 0;

	sp_ctl(sp);
}

static void sp_generate_sram_memory_image(sp_t *sp, char *program_name)
{
	FILE *fp;
	int addr, i;

	fp = fopen(program_name, "r");
	if (fp == NULL) {
		printf("couldn't open file %s\n", program_name);
		exit(1);
	}
	addr = 0;
	while (addr < SP_SRAM_HEIGHT) {
		fscanf(fp, "%08x\n", &sp->memory_image[addr]);
		addr++;
		if (feof(fp))
			break;
	}
	sp->memory_image_size = addr;

	fprintf(inst_trace_fp, "program %s loaded, %d lines\n", program_name);

	for (i = 0; i < sp->memory_image_size; i++)
		llsim_mem_inject(sp->sram, i, sp->memory_image[i], 31, 0);
}

static void sp_register_all_registers(sp_t *sp)
{
	sp_registers_t *spro = sp->spro, *sprn = sp->sprn;

	// registers
	llsim_register_register("sp", "r_0", 32, 0, &spro->r[0], &sprn->r[0]);
	llsim_register_register("sp", "r_1", 32, 0, &spro->r[1], &sprn->r[1]);
	llsim_register_register("sp", "r_2", 32, 0, &spro->r[2], &sprn->r[2]);
	llsim_register_register("sp", "r_3", 32, 0, &spro->r[3], &sprn->r[3]);
	llsim_register_register("sp", "r_4", 32, 0, &spro->r[4], &sprn->r[4]);
	llsim_register_register("sp", "r_5", 32, 0, &spro->r[5], &sprn->r[5]);
	llsim_register_register("sp", "r_6", 32, 0, &spro->r[6], &sprn->r[6]);
	llsim_register_register("sp", "r_7", 32, 0, &spro->r[7], &sprn->r[7]);

	llsim_register_register("sp", "pc", 16, 0, &spro->pc, &sprn->pc);
	llsim_register_register("sp", "inst", 32, 0, &spro->inst, &sprn->inst);
	llsim_register_register("sp", "opcode", 5, 0, &spro->opcode, &sprn->opc
	llsim_register_register("sp", "dst", 3, 0, &spro->dst, &sprn->dst);
	llsim_register_register("sp", "src0", 3, 0, &spro->src0, &sprn->src0);
	llsim_register_register("sp", "src1", 3, 0, &spro->src1, &sprn->src1);
	llsim_register_register("sp", "alu0", 32, 0, &spro->alu0, &sprn->alu0);
}

void sp_init(char *program_name)
{
	llsim_unit_t *llsim_sp_unit;
	llsim_unit_registers_t *llsim_ur;
	sp_t *sp;

	llsim_printf("initializing sp unit\n");

	inst_trace_fp = fopen("inst_trace.txt", "w");
	if (inst_trace_fp == NULL) {
		printf("couldn't open file inst_trace.txt\n");
		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);
}

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

#include "llsim.h"




		do {							\
			llsim_printf("sp: clock %d: ", llsim->clock);	\
			llsim_printf(a);				\
		} while (0)

int nr_simulated_instructions = 0;
FILE *inst_trace_fp = NULL, *cycle_trace_fp = NULL;


typedef struct sp_registers_s {
	// 6 32 bit registers (r[0], r[1] don't exist)
	int r[8];

	// 16 bit program counter
	int pc;

	// 32 bit instruction
	int inst;

	// 5 bit opcode
	int opcode;

	// 3 bit destination register index
	int dst;

	// 3 bit source #0 register index
	int src0;

	// 3 bit source #1 register index
	int src1;

	// 32 bit alu #0 operand
	int alu0;

	// 32 bit alu #1 operand
	int alu1;

	// 32 bit alu output
	int aluout;

	// 32 bit immediate field (original 16 bit sign extended)
	int immediate;

	// 32 bit cycle counter
	int cycle_counter;

	// 3 bit control state machine state register
	int ctl_state;

	// control states







} sp_registers_t;

/*
 * Master structure
 */
typedef struct sp_s {
	// local sram

	llsim_memory_t *sram;

	unsigned int memory_image[SP_SRAM_HEIGHT];
	int memory_image_size;

	sp_registers_t *spro, *sprn;
	int instruction_count;
	int start;
} sp_t;

static void sp_reset(sp_t *sp)
{
	sp_registers_t *sprn = sp->sprn;

	memset(sprn, 0, sizeof(*sprn));
}

/*
 * opcodes
 */

















static char opcode_name[32][4] = {"ADD", "SUB", "LSF", "RSF", "AND", "OR"
		"LD", "ST", "U", "U", "U", "U", "U", "U",
		"JLT", "JLE", "JEQ", "JNE", "JIN", "U", "U", "U",
		"HLT", "U", "U", "U", "U", "U", "U", "U"};

static void dump_sram(sp_t *sp)
{
	FILE *fp;
	int i;

	fp = fopen("sram_out.txt", "w");
	if (fp == NULL) {
		printf("couldn't open file sram_out.txt\n");
		exit(1);
	}
	for (i = 0; i < SP_SRAM_HEIGHT; i++)
		fprintf(fp, "%08x\n", llsim_mem_extract(sp->sram, i, 31, 0));
	fclose(fp);
}


static void sp_ctl(sp_t *sp)
{
	sp_registers_t *spro = sp->spro;
	sp_registers_t *sprn = sp->sprn;
	int i;
	char traceExecuteLine[100], traceExecuteLineContent[50],stringToP
	// sp_ctl

	fprintf(cycle_trace_fp, "cycle %d\n", spro->cycle_counter);
	for (i = 2; i <= 7; i++)
		fprintf(cycle_trace_fp, "r%d %08x\n", i, spro->r[i]);
	fprintf(cycle_trace_fp, "pc %08x\n", spro->pc);
	fprintf(cycle_trace_fp, "inst %08x\n", spro->inst);
	fprintf(cycle_trace_fp, "opcode %08x\n", spro->opcode);
	fprintf(cycle_trace_fp, "dst %08x\n", spro->dst);
	fprintf(cycle_trace_fp, "src0 %08x\n", spro->src0);
	fprintf(cycle_trace_fp, "src1 %08x\n", spro->src1);
	fprintf(cycle_trace_fp, "immediate %08x\n", spro->immediate);
	fprintf(cycle_trace_fp, "alu0 %08x\n", spro->alu0);
	fprintf(cycle_trace_fp, "alu1 %08x\n", spro->alu1);
	fprintf(cycle_trace_fp, "aluout %08x\n", spro->aluout);
	fprintf(cycle_trace_fp, "cycle_counter %08x\n", spro->cycle_counter);
	fprintf(cycle_trace_fp, "ctl_state %08x\n\n", spro->ctl_state);

	sprn->cycle_counter = spro->cycle_counter + 1;

	switch (spro->ctl_state) {
	case CTL_STATE_IDLE:
		sprn->pc = 0;
		sp->instruction_count = 0;
		if (sp->start)
			sprn->ctl_state = CTL_STATE_FETCH0;
		break;

	case CTL_STATE_FETCH0:
		llsim_mem_read(sp->sram, spro->pc);
		sprn->ctl_state = CTL_STATE_FETCH1;
		break;

	case CTL_STATE_FETCH1:
		sprn->inst = llsim_mem_extract_dataout(sp->sram, 31, 0);
		sprn->ctl_state = CTL_STATE_DEC0;
		break;

	case CTL_STATE_DEC0:
		sprn->opcode = ((0x3e000000 & spro->inst) >> 25);
		sprn->dst = ((0x01c00000 & spro->inst) >> 22);
		sprn->src0 = ((0x00380000 & spro->inst) >> 19);
		sprn->src1 = ((0x00070000 & spro->inst) >> 16);
		sprn->immediate = (((0x0000ffff & spro->inst) << 16)>>16);
		sprn->ctl_state = CTL_STATE_DEC1;
		break;

	case CTL_STATE_DEC1:

		if (spro->src0==0)
			sprn->alu0 = 0;
		else if (spro->src0==1)
			sprn->alu0 = spro->immediate;
		else
			sprn->alu0 = spro->r[spro->src0];

		if (spro->src1==0)
			sprn->alu1 = 0;
		else if (spro->src1==1)
			sprn->alu1 = spro->immediate;
		else
			sprn->alu1 = spro->r[spro->src1];

		//Print the trace (not including the EXEC part)
		sprintf(stringToPrint,"\n--- instruction %d (%04x) @ PC %d (%04d)",
				sp->instruction_count, sp->instruction_count,
				spro->pc, spro->pc);
		sprintf(temp," ------------------------------------------------------
		strcat(stringToPrint,temp);
		sprintf(temp,"pc = %04d, inst = %08x, ", spro->pc, spro->inst);
		strcat(stringToPrint,temp);
		sprintf(temp,"opcode = %d (%s)", spro->opcode, opcode_name[spro->opcod
		strcat(stringToPrint,temp);
		sprintf(temp,", dst = %d, src0 = %d, ", spro->dst, spro->src0);
		strcat(stringToPrint,temp);
		sprintf(temp,"src1 = %d, immediate = %08x\n", spro->src1, spro->immedia
		strcat(stringToPrint,temp);
		int i,reg;
		for (i=0; i<8; i++)
		{
			if (i==0)
				reg = 0;
			else if (i==1)
				reg = spro->immediate;
			else
				reg = sprn->r[i];

			sprintf(temp,"r[%d] = %08x ", i, reg);
			strcat(stringToPrint,temp);
			if (!((i+1)%4))
				strcat(stringToPrint,"\n");
		}
		fprintf(inst_trace_fp,"%s",stringToPrint);


		sprn->ctl_state = CTL_STATE_EXEC0;

		break;

	case CTL_STATE_EXEC0:

		switch (spro->opcode)
		{

		case ADD:
			sprn->aluout = spro->alu0 + spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case SUB:
			sprn->aluout = spro->alu0 - spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LSF:
			sprn->aluout = spro->alu0 << spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case RSF:
			sprn->aluout = spro->alu0 >> spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case AND:
			sprn->aluout = spro->alu0 & spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case OR:
			sprn->aluout = spro->alu0 | spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case XOR:
			sprn->aluout = spro->alu0 ^ spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LHI:
			sprn->aluout = (spro->alu1 << 16) | (spro->alu0 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case LD:
			llsim_mem_read(sp->sram, spro->alu1 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case ST:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLT:
			sprn->aluout = spro->alu0 < spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLE:
			sprn->aluout = spro->alu0 <= spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JEQ:
			sprn->aluout =  spro->alu0 == spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JNE:
			sprn->aluout = spro->alu0 != spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JIN:
		case HLT:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;
		default:
			// Invalid OPCODE, go to fetch0
			sprn->pc = (spro->pc + 1) & 0xffff;
			sprn->ctl_state = CTL_STATE_FETCH0;
			break;
		}
		break;


				fprintf(inst_trace_fp,"%s",traceExecuteLine);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				break;
			}

			switch (spro->opcode)
			{

			case ADD:
			case SUB:
			case LSF:
			case RSF:
			case AND:
			case OR:
			case XOR:
			case LHI:
				sprn->r[spro->dst] = spro->aluout;
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						TRACE_EXEC_ARITH_CONTENT_LINE_PATTERN,
				break;

			case LD:
				sprn->r[spro->dst] = llsim_mem_extract_dataout(sp->sram, 31,
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"R[%d] = MEM[%d] = %08x ",
						spro->dst, spro->alu1,
						sprn->r[spro->dst]);
				break;

			case ST:
				llsim_mem_set_datain(sp->sram, spro->alu0, 31, 0);
				llsim_mem_write(sp->sram, spro->alu1 & 0xffff);
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"MEM[%d] = R[%d] = %08x ",
						spro->alu1, spro->src0, spro->alu0);
				break;

			case JLT:
			case JLE:
			case JEQ:
			case JNE:
				if (spro->aluout){
					sprn->r[7] = spro->pc;
					sprn->pc = spro->immediate;
				}else
					sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ",opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case JIN:
				sprn->r[7] = spro->pc;
				sprn->pc = spro->alu0;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, %d, %d ", opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;

			case HLT:
				sprn->ctl_state = CTL_STATE_IDLE;
				sprintf(traceExecuteLineContent,
						"HALT at PC %04x", spro->pc);
				llsim_stop();
				dump_sram(sp);
				break;

			default:
				// Invalid OPCODE, go to fetch0
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				traceExecuteLineContent[0]=0;
				break;
			}

			//Print the execution line to trace
			sprintf(traceExecuteLine, TRACE_EXEC_LINE_PATTERN, traceExecuteLin
            intf(inst_trace_fp,"%s",traceExecuteLine);
			sp->instruction_count = sp->instruction_count+1;

			//Print the final line to trace
			if (spro->opcode==HLT){
				char stringToPrint[100];
				sprintf(stringToPrint,"sim finished at pc %d, %d instructi
                ons",spro->pc,sp->instruction_count);
				fprintf(inst_trace_fp,"%s",stringToPrint);
				fclose(inst_trace_fp);
			}

			sprn->pc = sprn->pc & 0xffff;

			break;
	}
}

static void sp_run(llsim_unit_t *unit)
{
	sp_t *sp = (sp_t *) unit->private;

	if (llsim->reset) {
		sp_reset(sp);
		return;
	}

	sp->sram->read = 0;
	sp->sram->write = 0;

	sp_ctl(sp);
}

static void sp_generate_sram_memory_image(sp_t *sp, char *program_name)
{
	FILE *fp;
	int addr, i;

	fp = fopen(program_name, "r");
	if (fp == NULL) {
		printf("couldn't open file %s\n", program_name);
		exit(1);
	}
	addr = 0;
	while (addr < SP_SRAM_HEIGHT) {
		fscanf(fp, "%08x\n", &sp->memory_image[addr]);
		addr++;
		if (feof(fp))
			break;
	}
	sp->memory_image_size = addr;

	fprintf(inst_trace_fp, "program %s loaded, %d lines\n", program_name);

	for (i = 0; i < sp->memory_image_size; i++)
		llsim_mem_inject(sp->sram, i, sp->memory_image[i], 31, 0);
}

static void sp_register_all_registers(sp_t *sp)
{
	sp_registers_t *spro = sp->spro, *sprn = sp->sprn;

	// registers
	llsim_register_register("sp", "r_0", 32, 0, &spro->r[0], &sprn->r[0]);
	llsim_register_register("sp", "r_1", 32, 0, &spro->r[1], &sprn->r[1]);
	llsim_register_register("sp", "r_2", 32, 0, &spro->r[2], &sprn->r[2]);
	llsim_register_register("sp", "r_3", 32, 0, &spro->r[3], &sprn->r[3]);
	llsim_register_register("sp", "r_4", 32, 0, &spro->r[4], &sprn->r[4]);
	llsim_register_register("sp", "r_5", 32, 0, &spro->r[5], &sprn->r[5]);
	llsim_register_register("sp", "r_6", 32, 0, &spro->r[6], &sprn->r[6]);
	llsim_register_register("sp", "r_7", 32, 0, &spro->r[7], &sprn->r[7]);

	llsim_register_register("sp", "pc", 16, 0, &spro->pc, &sprn->pc);
	llsim_register_register("sp", "inst", 32, 0, &spro->inst, &sprn->inst);
	llsim_register_register("sp", "opcode", 5, 0, &spro->opcode, &sprn->opc
	llsim_register_register("sp", "dst", 3, 0, &spro->dst, &sprn->dst);
	llsim_register_register("sp", "src0", 3, 0, &spro->src0, &sprn->src0);
	llsim_register_register("sp", "src1", 3, 0, &spro->src1, &sprn->src1);
	llsim_register_register("sp", "alu0", 32, 0, &spro->alu0, &sprn->alu0);
}

void sp_init(char *program_name)
{
	llsim_unit_t *llsim_sp_unit;
	llsim_unit_registers_t *llsim_ur;
	sp_t *sp;

	llsim_printf("initializing sp unit\n");

	inst_trace_fp = fopen("inst_trace.txt", "w");
	if (inst_trace_fp == NULL) {
		printf("couldn't open file inst_trace.txt\n");
		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->start = 1;

	sp_register_all_registers(sp);
}